1. 简介
本节非规范性。
本规范定义了一套 API,使得由 作用域化 的、可证明的基于公钥的强凭证能够被 web 应用 创建和使用,以便对用户进行强认证。公钥凭证 由 WebAuthn Authenticator 按 WebAuthn Relying Party 的请求创建并存储,前提是获得了 用户同意。随后,公钥凭证 只能被属于该 Relying Party 的 origin 访问。该作用域性由 符合性用户代理 与 authenticators 共同强制执行。此外,不同 Relying Parties 之间的隐私也得到维护;Relying Parties 无法检测到其它为不同 Relying Parties 作用域化 的凭证的任何属性,甚至无法检测其是否存在。
Relying Parties
在涉及用户的两个不同但相关的仪式期间使用 Web
Authentication API。第一个是 注册,在此期间,在 authenticator 上创建一个 公钥凭证,并将其 作用域化 到具有当前用户账户的 Relying Party(该账户可能已存在,也可能在此时创建)。第二个是 认证,在此期间,Relying Party 会收到一个证明已注册该 公钥凭证 的用户在场和同意的 认证断言。从功能上讲,Web Authentication API 包括扩展凭证管理
API 的 PublicKeyCredential,以及允许通过
navigator.credentials.create()
和 navigator.credentials.get()
使用这些凭证的基础设施。前者用于 注册,后者用于 认证。
总体而言,符合规范的 authenticators 保护 公钥凭证,并与用户代理交互以实现 Web Authentication API。符合规范的认证器可以通过在以下环境中的软件实现来实现:(a) 在通用计算设备上执行,(b) 在设备内的安全执行环境、可信平台模块 (TPM) 或 安全元件 (SE) 上,或 (c) 在设备外部。部署在设备上的认证器称为 平台认证器。部署在设备外的认证器(漫游认证器)可以通过诸如通用串行总线 (USB)、蓝牙低能耗 (BLE) 或近场通信 (NFC) 等传输方式访问。
1.1. 规范路线图
尽管许多 W3C 规范主要针对用户代理开发者,同时也面向 Web 应用开发者(即“Web 作者”),但 Web Authentication 的性质要求本规范为多类受众正确使用,如下所述。
所有受众 应当从 § 1.2 用例、§ 1.3 示例 API 使用场景 和 § 4 术语 开始,并且还应参考 [WebAuthnAPIGuide] 以获得总体教程。除此之外,本文档的目标读者主要包括以下几类群体:
-
Relying Party Web 应用开发者,特别是负责 Relying Party web 应用 登录流程、账户恢复流程、用户账户数据库内容等的开发者。
-
Web 框架开发者
-
上述两类受众应特别参考 § 7 WebAuthn Relying Party Operations。阅读 § 5 Web Authentication API 的引言可能有帮助,但读者应意识到 § 5 Web Authentication API 部分主要针对用户代理开发者,而不是 Web 应用开发者。此外,如果他们打算验证 authenticator 的 attestations,那么 § 6.5 Attestation 和 § 8 已定义的证明语句格式 也将相关。若希望使用扩展,还应参阅 § 9 WebAuthn Extensions 和 § 10 已定义的扩展。最后,他们应阅读 § 13.4 针对 Relying Parties 的安全性考虑 和 § 14.6 针对 Relying Parties 的隐私考虑,并考虑哪些挑战适用于其应用及用户。
-
-
用户代理开发者
-
操作系统平台开发者,负责与平台特定 authenticator API 相关的 OS 平台 API 设计与实现、平台 WebAuthn Client 实例化等。
-
上述两类受众应仔细阅读 § 5 Web Authentication API,如果打算支持扩展还应阅读 § 9 WebAuthn Extensions。他们还应仔细阅读 § 14.5 针对客户端的隐私考虑。
-
-
Authenticator 开发者。此类读者应特别关注 § 6 WebAuthn Authenticator Model、§ 8 已定义的证明语句格式、§ 9 WebAuthn Extensions 和 § 10 已定义的扩展。他们还应仔细阅读 § 13.3 针对认证器的安全性考虑 和 § 14.4 针对认证器的隐私考虑。
对于 Web Authentication 部署的端到端安全而言非常重要的一点是 各组件(即 Relying Party 服务器、client 与 authenticator)的角色,以及 § 13 安全性考虑 和 § 14 隐私考虑,应由 所有受众 所理解。
1.2. 用例
下面的用例场景展示了两种非常不同类型的 authenticators 和凭证在两种常见部署类型中的使用方式,并概述了其它场景。附加场景(含示例代码)稍后在 § 1.3 示例 API 使用场景 中给出。这些示例仅用于说明,功能可用性在不同客户端与认证器实现之间可能有所不同。
1.2.1. 具有多设备凭证的消费者
该用例说明了面向消费者的 Relying Party 如何利用用户设备内置的认证器,通过使用 多设备凭证(通常称为已同步的 passkeys)来提供抗钓鱼的登录。
1.2.1.1. 注册
-
在手机上:
-
用户在浏览器中导航至 example.com 并使用其原有方法(可能是诸如密码之类的传统方式)登录现有账户,或创建新账户。
-
手机提示:“是否要为 example.com 创建一个 passkey?”
-
用户同意。
-
手机提示用户输入先前配置的 授权手势(PIN、生物识别等);用户提供该手势。
-
网站显示消息:“注册完成。”
-
1.2.1.2. 认证
-
在笔记本或台式机上:
-
接下来,在他们的手机上:
-
用户会看到一个离散的提示或通知:“为 example.com 登录”。
-
用户选择该提示 / 通知。
-
用户看到其 example.com 身份的列表,例如 “以 Mohamed 登录 / 以 张三 登录”。
-
用户选择一个身份,系统提示输入 授权手势(PIN、生物识别等),用户提供该手势。
-
-
现在,回到笔记本上:
-
网页显示所选用户已登录,并导航至已登录页面。
-
1.2.2. 具有单设备凭证的员工
该用例说明了面向员工的 Relying Party 如何结合使用 漫游认证器(例如 USB 安全密钥)和 平台认证器(例如内置指纹传感器),以便用户拥有:
-
一个可作为“主用”的 漫游认证器,用于在对用户而言新的客户端设备(例如笔记本、台式机)上进行身份验证,或在缺乏 平台认证器 的客户端设备上进行身份验证,
-
一种在具备 平台认证器 的客户端设备上进行低摩擦强认证的方式,或
-
一种在具备某些不支持 单设备凭证(通常称为设备绑定的 passkeys)的 passkey 平台认证器 的客户端设备上强认证的方法。
1.2.2.1. 注册
在此示例中,用户的雇主邮寄了一个预配置了设备绑定 passkey 的安全密钥给用户。
一个临时 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,并被引导完成在该安全密钥上创建并注册凭证的流程。
-
Relying Party 提示用户提供其 授权手势 以授权单笔交易,例如支付或其它金融交易。
1.3. 示例 API 使用场景
本节非规范性。
在本节中,我们将演示 公钥凭证 生命周期中的若干事件,并给出使用本 API 的相应示例代码。请注意这只是一个示例流程,并不限制 API 的使用范围。
正如前面部分所示,该流程聚焦于具有自身显示屏的 passkey 漫游认证器 的用例。此类认证器的一个示例是智能手机。本 API 也支持其它类型的认证器,前提是由 client platform 实现。例如,该流程对于嵌入在 客户端设备 中的认证器也无需修改即可工作。对于没有自身显示屏的认证器(类似智能卡)的情况,该流程也可工作,但需考虑特定实现细节。具体地,client platform 需要显示任何本应由认证器显示的提示,且认证器需允许 client platform 枚举认证器的所有凭证,以便客户端能够显示合适的提示信息。
1.3.1. 注册
这是首次流程,其中创建新凭证并向服务器注册。在此流程中,WebAuthn Relying Party 对平台认证器或漫游认证器均无偏好。
-
用户访问 example.com,页面提供了一个脚本。此时,用户可能已经使用传统用户名与密码或其它 Relying Party 可接受的方式登录,或正在创建新账户。
-
Relying Party 脚本运行下面的代码段。
-
client platform 搜索并定位认证器。
-
client 连接到认证器,并在必要时执行配对操作。
-
认证器显示适当的 UI,提示用户提供生物识别或其它 授权手势。
-
认证器向 client 返回响应,client 将响应返回给 Relying Party 脚本。如果用户拒绝选择认证器或提供授权,则返回相应错误。
-
如果创建了新凭证,
-
Relying Party 脚本将新生成的 凭证公钥 发送到服务器,并附带诸如来自认证器的来源与特性相关的证明(attestation)等附加信息。
-
服务器将 凭证公钥 存储在其数据库中,并将其与用户以及 attestation 指示的认证特性关联,同时为日后使用存储一个便于识别的友好名称。
-
脚本可能将诸如 凭证 ID 等数据存入本地存储,以通过缩小用户凭证选择范围来提升未来的用户体验。
-
下面是生成并注册新密钥的示例代码:
if ( ! window. PublicKeyCredential) { /* Client not capable. Handle error. */ } var publicKey= { // The challenge is produced by the server; see the Security Considerations challenge: new Uint8Array([ 21 , 31 , 105 /* 29 more random bytes generated by the server */ ]), // Relying Party: rp: { name: "ACME Corporation" }, // User: user: { id: Uint8Array. from ( window. atob( "MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII=" ), c=> c. charCodeAt( 0 )), name: "alex.mueller@example.com" , displayName: "Alex Müller" , }, // This Relying Party will accept either an ES256 or RS256 credential, but // prefers an ES256 credential. pubKeyCredParams: [ { type: "public-key" , alg: - 7 // "ES256" as registered in the IANA COSE Algorithms registry }, { type: "public-key" , alg: - 257 // Value registered by this specification for "RS256" } ], authenticatorSelection: { // Try to use UV if possible. This is also the default. userVerification: "preferred" }, timeout: 300000 , // 5 minutes excludeCredentials: [ // Don't re-register any authenticator that has one of these credentials { "id" : Uint8Array. from ( window. atob( "ufJWp8YGlibm1Kd9XQBWN1WAw2jy5In2Xhon9HAqcXE=" ), c=> c. charCodeAt( 0 )), "type" : "public-key" }, { "id" : Uint8Array. from ( window. atob( "E/e1dhZc++mIsz4f9hb6NifAzJpF1V4mEtRlIPBiWdY=" ), c=> c. charCodeAt( 0 )), "type" : "public-key" } ], // Make excludeCredentials check backwards compatible with credentials registered with U2F extensions: { "appidExclude" : "https://acme.example.com" } }; // Note: The following call will cause the authenticator to display UI. navigator. credentials. create({ publicKey}) . then( function ( newCredentialInfo) { // Send new credential info to server for verification and registration. }). catch ( function ( err) { // No acceptable authenticator or user refused consent. Handle appropriately. });
1.3.2. 专门针对用户验证的平台认证器的注册
当 WebAuthn Relying Party 特别希望创建一个使用 用户验证平台认证器 的 公钥凭证 时,以下为示例流程。
-
用户访问 example.com 并点击登录按钮,登录按钮将用户重定向至 login.example.com。
-
用户输入用户名和密码登录。登录成功后,用户被重定向回 example.com。
-
Relying Party 脚本运行下面的代码段。
-
用户代理检查是否有 用户验证平台认证器 可用。如果没有,则终止此流程。
-
Relying Party 询问用户是否希望与其创建凭证。如果不同意,则终止此流程。
-
用户代理和/或操作系统显示相应 UI,并引导用户使用可用的平台认证器创建凭证。
-
凭证创建成功后,Relying Party 脚本将新凭证传送给服务器。
-
if ( ! window. PublicKeyCredential) { /* Client not capable of the API. Handle error. */ } PublicKeyCredential. isUserVerifyingPlatformAuthenticatorAvailable() . then( function ( uvpaAvailable) { // If there is a user-verifying platform authenticator if ( uvpaAvailable) { // Render some RP-specific UI and get a Promise for a Boolean value return askIfUserWantsToCreateCredential(); } }). then( function ( userSaidYes) { // If there is a user-verifying platform authenticator // AND the user wants to create a credential if ( userSaidYes) { var publicKeyOptions= { /* Public key credential creation options. */ }; return navigator. credentials. create({ "publicKey" : publicKeyOptions}); } }). then( function ( newCredentialInfo) { if ( newCredentialInfo) { // Send new credential info to server for verification and registration. } }). catch ( function ( err) { // Something went wrong. Handle appropriately. });
1.3.3. 认证
当具有已注册凭证的用户访问网站并希望使用该凭证进行认证时,这是该流程。
-
用户访问 example.com,页面提供了一个脚本。
-
脚本向 client 请求一个认证断言(Authentication Assertion),并尽可能提供多的信息以缩小对用户可接受凭证的选择范围。这些信息可以来自注册后本地存储的数据,或通过提示用户输入用户名等方式获取。
-
Relying Party 脚本运行下面的代码片段之一。
-
client platform 搜索并定位认证器。
-
client 连接到认证器,并在必要时执行配对操作。
-
认证器向用户展示需要其注意的通知。打开通知后,用户会看到一个友好的可接受凭证选择菜单,菜单使用创建凭证时提供的账户信息,并展示请求这些密钥的 origin 的部分信息。
-
认证器从用户处获取生物识别或其它 授权手势。
-
认证器向 client 返回响应,client 将响应返回给 Relying Party 脚本。如果用户拒绝选择凭证或提供授权,则返回相应错误。
-
如果成功生成并返回断言,则:
-
脚本将断言发送到服务器。
-
服务器检查断言,提取 凭证 ID,在其数据库中查找已注册的凭证公钥,并验证断言签名。如果验证通过,服务器会查找与断言的 凭证 ID 相关联的身份;该身份即被认证。如果服务器无法识别该 凭证 ID(例如因不活跃而已被注销),则认证失败;每个 Relying Party 将按自己的方式处理此情况。
-
服务器随后执行在成功认证后应执行的操作——返回成功页面、设置认证 cookie 等。
-
如果 Relying Party 脚本没有任何可用的提示(例如来自本地存储的数据)来帮助缩小凭证列表,则执行此类认证的示例代码可能如下所示:
if ( ! window. PublicKeyCredential) { /* Client not capable. Handle error. */ } // credentialId is generated by the authenticator and is an opaque random byte array var credentialId= new Uint8Array([ 183 , 148 , 245 /* more random bytes previously generated by the authenticator */ ]); var options= { // The challenge is produced by the server; see the Security Considerations challenge: new Uint8Array([ 4 , 101 , 15 /* 29 more random bytes generated by the server */ ]), timeout: 300000 , // 5 minutes allowCredentials: [{ type: "public-key" , id: credentialId}] }; navigator. credentials. get({ "publicKey" : options}) . then( function ( assertion) { // Send assertion to server for verification }). catch ( function ( err) { // No acceptable credential or user refused consent. Handle appropriately. });
另一方面,如果 Relying Party 脚本具有一些提示以帮助缩小凭证列表,则执行此类认证的示例代码可能如下所示。请注意此示例同时演示了如何使用 凭证属性扩展(Credential Properties Extension)。
if ( ! window. PublicKeyCredential) { /* Client not capable. Handle error. */ } var encoder= new TextEncoder(); var acceptableCredential1= { type: "public-key" , id: encoder. encode( "BA44712732CE" ) }; var acceptableCredential2= { type: "public-key" , id: encoder. encode( "BG35122345NF" ) }; var options= { // The challenge is produced by the server; see the Security Considerations challenge: new Uint8Array([ 8 , 18 , 33 /* 29 more random bytes generated by the server */ ]), timeout: 300000 , // 5 minutes allowCredentials: [ acceptableCredential1, acceptableCredential2], extensions: { 'credProps' : true } }; navigator. credentials. get({ "publicKey" : options}) . then( function ( assertion) { // Send assertion to server for verification }). catch ( function ( err) { // No acceptable credential or user refused consent. Handle appropriately. });
1.3.4. 中止认证操作
下面的示例展示了开发者如何使用 AbortSignal 参数来中止凭证注册操作。对认证操作同样适用类似过程。
const authAbortController= new AbortController(); const authAbortSignal= authAbortController. signal; authAbortSignal. onabort= function () { // Once the page knows the abort started, inform user it is attempting to abort. } var options= { // A list of options. } navigator. credentials. create({ publicKey: options, signal: authAbortSignal}) . then( function ( attestation) { // Register the user. }). catch ( function ( error) { if ( error== "AbortError" ) { // Inform user the credential hasn't been created. // Let the server know a key hasn't been created. } }); // Assume widget shows up whenever authentication occurs. if ( widget== "disappear" ) { authAbortController. abort(); }
1.3.5. 退役
以下为在服务器端希望退役凭证的若干可能情形。请注意,所有这些情形均由服务器端处理,无需本规范所定义的 API 提供额外支持。
-
可能性 #1 —— 用户报告凭证丢失。
-
用户访问 server.example.net,进行身份验证并点击链接以报告丢失/被盗的 authenticator。
-
服务器返回页面,显示注册凭证列表及注册时配置的友好名称。
-
用户选择一个凭证,服务器从其数据库中将其删除。
-
以后,Relying Party 脚本不会在任何可接受凭证的列表中指定该凭证,并且由该凭证签名的断言将被拒绝。
-
-
可能性 #2 —— 服务器因不活跃而注销该凭证。
-
服务器在维护活动中从其数据库中删除该凭证。
-
以后,Relying Party 脚本不会在任何可接受凭证的列表中指定该凭证,并且由该凭证签名的断言将被拒绝。
-
-
可能性 #3 —— 用户从 authenticator 中删除了该凭证。
-
用户使用认证器特定的方法(例如设备设置 UI)从其 authenticator 中删除凭证。
-
从此以后,该凭证不会出现在任何选择提示中,也无法用它生成断言。
-
之后某个时间,服务器可能因不活跃而注销该凭证。
-
1.4. 平台特定实现指南
本规范定义了在通用情况下如何使用 Web Authentication。当在与特定平台支持(例如应用)相关的场景中使用 Web Authentication 时,建议查阅平台特定的文档和指南以获得额外的指导和限制说明。
2. 符合性
本规范定义了三种符合性类别。每一类的规范性成员都被指定为能够抵御来自其他类别中不符合规范或敌对成员的攻击。
2.1. 用户代理
用户代理必须按照 § 5 Web Authentication API 中的描述进行行为,才能被视为符合规范。符合性用户代理 可以以任何希望的方式实现本规范中给出的算法,只要最终结果与规范算法所描述的结果无法区分。
符合规范的用户代理还必须作为本规范的 IDL 片段的符合性实现,如 “Web IDL” 规范中所述。[WebIDL]
2.1.1. 将枚举作为 DOMString 类型的向后兼容性
枚举类型未在 Web IDL 的其它部分中被引用,因为那样会排除在不更新规范及其实现的情况下使用其他值的可能性。为了向后兼容,客户端平台 和 Relying Parties
处理未知值非常重要。本规范的枚举用于文档记录和作为登记表。当这些枚举在其它位置表示时,它们被标记为 DOMString
类型,例如在 transports
中。
2.2. 认证器
WebAuthn Authenticator 必须提供 § 6 WebAuthn Authenticator Model 中定义的操作,并且这些操作必须按该部分中所述进行。这是一组功能与安全要求,使得认证器可被 符合性用户代理 使用。
如 § 1.2 用例 所述,认证器可以实现于用户代理所依赖的操作系统中、外部硬件中,或两者的组合中。
2.2.1. 与 FIDO U2F 的向后兼容性
仅支持 § 8.6 FIDO U2F 证明语句格式 的 Authenticators 无法存储 user handle,因此返回的 userHandle
将始终为 null。
2.3. WebAuthn Relying Parties
WebAuthn Relying Party 必须按照 § 7 WebAuthn Relying Party Operations 中的描述进行行为,以获得本规范提供的所有安全收益。有关更多讨论,请参见 § 13.4.1 WebAuthn Relying Parties 的安全性优势。
2.4. 所有符合性类别
上述所有符合性类别成员执行的所有 CBOR 编码必须使用 CTAP2 规范的规范化 CBOR 编码形式。上述符合性类别的所有解码器应拒绝不按 CTAP2 规范化 CBOR 编码形式 有效编码的 CBOR,并且应当拒绝具有重复映射键的消息。
3. 依赖项
本规范依赖若干其它底层规范,下列列出,并在 通过引用定义的术语 中也有列出。
- Base64url encoding
-
术语 Base64url Encoding 指的是使用 [RFC4648] 第 5 节中定义的、对 URL 和文件名安全的字符集的 base64 编码,去掉所有尾随的 '=' 字符(如第 3.2 节允许的)并且不包含任何换行、空白或其它额外字符。
- CBOR
-
本规范中的若干结构(包括 attestation 语句和扩展)采用 Compact Binary Object Representation(CBOR)的 CTAP2 规范化 CBOR 编码形式 编码,如 [RFC8949] 所定义,并依照 [FIDO-CTAP] 的规定。
- CDDL
- COSE
-
CBOR 对象签名与加密(COSE)参见 [RFC9052] 与 [RFC9053]。还使用了由 [IANA-COSE-ALGS-REG] 管理的 IANA COSE 算法注册表,该注册表最初由 [RFC8152] 建立,并由上述规范更新。
- Credential Management
-
本文档所述的 API 是对在 [CREDENTIAL-MANAGEMENT-1] 中定义的
Credential概念的扩展。 - DOM
-
DOMException及本文规范中使用的 DOMException 值在 [DOM4] 中定义。 - ECMAScript
-
%ArrayBuffer% 在 [ECMAScript] 中定义。
- URL
-
domain、host、port、scheme、valid domain 和 valid domain string 等概念在 [URL] 中定义。
- Web IDL
-
本规范中的许多接口定义以及所有 IDL 均依赖于 [WebIDL]。该更新版本的 Web IDL 标准增加了对
Promise的支持,Promise 现在是所有新 Web API 中首选的异步交互机制。 - FIDO AppID
-
用于 确定调用应用的 FacetID 以及 确定调用者的 FacetID 是否被授权用于某 AppID 的算法(仅在 AppID 扩展 中使用)由 [FIDO-APPID] 定义。
文中关键字 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", 和 "OPTIONAL" 的解释应按照 BCP 14 的描述在 [RFC2119] 与 [RFC8174] 中的说明来理解,但仅当这些词以全大写形式出现时才适用,如本文所示。
4. 术语
- Attestation
-
一般来说,attestation(证明) 是一种用于证明、确认或鉴别的陈述。在 WebAuthn 场景中,attestation 用于提供可验证的证据,证明某个 authenticator 的来源及其所发出的数据。这包括诸如 credential ID、凭证密钥对、签名计数器 等。
在 注册 仪式期间,会在 attestation object 中提供一个 attestation statement。另见 § 6.5 Attestation 与 图 6。关于 client 是否以及如何将 attestation statement 与 aaguid 部分的 attestation object 传送给 Relying Party,请参阅由 attestation conveyance 所描述的内容。
- Attestation Certificate
-
用于 attestation key pair 的 X.509 证书,该密钥对由 authenticator 用以证明其制造来源和能力。在 注册 时,authenticator 使用其 attestation private key 对其生成并通过 authenticatorMakeCredential 操作返回的 Relying Party-特定的 credential public key(及其它数据)进行签名。Relying Parties 使用在 attestation certificate 中携带的 attestation public key 来验证 attestation signature。注意在 self attestation 的情况下,authenticator 没有单独的 attestation key pair 或 attestation certificate;详见 self attestation 的说明。
- Authentication
- Authentication Ceremony
-
指的是一个ceremony,在该过程中,用户及包含或连接至少一个 authenticator 的用户 client platform 协同工作,通过密码学方式向 Relying Party 证明用户控制先前注册的 credential private key(见 Registration)。这包括 用户存在性测试 或 用户验证。
WebAuthn 的 authentication ceremony 在 § 7.2 验证认证断言 中定义,由 Relying Party 调用带有
publicKey参数的操作来发起。参见 § 5 Web Authentication API 的介绍性概览和 § 1.3.3 认证 的实现示例。navigator.credentials.get() - Authentication Assertion
- Assertion
-
由 authenticator 在执行 authenticatorGetAssertion 操作后返回的经加密签名的
AuthenticatorAssertionResponse对象。这对应于 [CREDENTIAL-MANAGEMENT-1] 规范中所述的一次性使用的 credentials 概念。
- Authenticator
- WebAuthn Authenticator
-
一种存在于硬件或软件中的密码学实体,能够在给定的 Relying Party 上为用户执行 register 操作,并在稍后对所注册的 public key credential 证明其拥有权(assert possession),并可选地向 Relying Party 进行 用户验证。Authenticators 在注册和断言期间可以通过 attestation 报告其类型和安全特性。
WebAuthn Authenticator 可以是 漫游认证器、集成到 客户端设备 的专用硬件子系统,或者客户端或客户端设备的一个软件组件。WebAuthn Authenticator 不必局限于本地上下文运行,可以在客户端外部的服务器上生成或存储 credential key pair。
一般假定一个 authenticator 仅有一个用户。如果多个自然人共享对某个 authenticator 的访问,则在该 authenticator 的上下文中,他们被视为代表同一用户。如果某个 authenticator 实现支持在隔离区中为多用户提供支持,则每个隔离区被视为具有单个用户且彼此之间无法访问对方凭证的独立 authenticator。
- Authorization Gesture
-
authorization gesture 指用户在仪式(如 registration 或 authentication)过程中与认证器进行的物理交互。通过施加这样的 authorization gesture,用户对该ceremony 的继续表示 同意(即授权)。如果认证器具备能力,这可能涉及 用户验证,也可能仅涉及简单的 用户存在性测试。
- Backed Up
-
Public Key Credential Sources 可能以某种方式被备份,以便它们可以出现在生成它们的 generating authenticator 之外的其它认证器上。备份可以通过包括但不限于点对点同步、云同步、局域网同步和手动导入/导出等机制进行。另见 § 6.1.3 凭证备份状态。
- Backup
Eligibility
- Backup Eligible
-
一个 公钥凭据源 的 生成认证器 会在创建时确定该 公钥凭据源 是否允许被 备份。备份资格通过 认证器数据 的 标志 与当前 备份状态 一起标识。 备份资格属于一种 凭据属性,对于给定的 公钥凭据源 是永久不变的。 具有备份资格的 公钥凭据源 被称为 多设备凭据,而不具备备份资格的则称为 单设备凭据。另见 § 6.1.3 凭据备份状态。
- Backup State
-
由当前的 managing authenticator 决定的 multi-device credential 的当前备份状态。备份状态通过 authenticator data 的 flags 指示,且可随时间变化。另见 backup eligibility 及 § 6.1.3 凭证备份状态。
- Biometric Authenticator
-
任一实现了 biometric recognition 的 authenticator。
- Biometric Recognition
-
基于生物和行为特征对个体进行自动识别的过程,参见 [ISOBiometricVocabulary]。
- Bound
credential
- "Authenticator contains a credential"
- "Credential created on an authenticator"
- "Authenticator contains a credential"
-
当一个 public key credential source 或 public key credential 被称为 bound 于它的 managing authenticator 时,意味着只有该 managing authenticator 能为绑定到它的 public key credential sources 生成 assertions。
这也可以表述为“managing authenticator contains 该 bound credential”,或“该 bound credential 是在其 managing authenticator 上 created on 的”。注意,服务器端凭证(server-side credential)可能并不物理存储在认证器的持久内存中,因此“bound to” 是主要术语。另见 § 6.2.2 凭证存储方式。
- Ceremony
-
ceremony 的概念(参见 [Ceremony])是对网络协议概念的扩展,加入了人类节点与计算机节点并存以及包含用户界面、人对人通信与承载数据的物理对象转移的通信链路。对协议来说的带外(out-of-band)在仪式中是带内(in-band)。在本规范中,Registration 与 Authentication 都是仪式,而 authorization gesture 通常是这些 ceremonies 的组成部分。
- Client
- WebAuthn Client
-
此处亦简称为 client。另见 Conforming User Agent。WebAuthn Client 是一个中介实体,通常在用户代理内(全部或部分)实现。从概念上讲,它承载 Web Authentication API 的实现,并实现
[[Create]](origin, options, sameOriginWithAncestors)与[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)等内部方法。它负责为底层的 authenticator operations 进行输入编排,并将这些操作的结果返回给 Web Authentication API 的调用者。WebAuthn Client 在 WebAuthn Client Device 上运行,且与其是不同的实体。
- Client
Device
- WebAuthn Client Device
-
运行 WebAuthn Client 的硬件设备,例如智能手机、笔记本或台式机,以及在该硬件上运行的操作系统。
下列是 WebAuthn Client device 与 client 之间的区别:
-
单个 client device 可以支持运行多个 clients(例如多个浏览器实现),这些客户端都能访问该 client device 上可用的相同 authenticators;
-
平台认证器 是绑定到 client device 而不是绑定到 WebAuthn Client 的。
-
- Client Platform
-
client device 与 client 合在一起构成 client platform。单一硬件设备可通过运行不同的操作系统和/或 clients 在不同时间成为多个不同的 client platforms 的一部分。
- Client-Side
-
通常指用户的 client platform、authenticators 及连接这些组件的一切部分的组合。
- Client-side discoverable Public Key
Credential Source
- Client-side discoverable Credential
- Discoverable Credential
- Passkey
- [DEPRECATED] Resident Credential
- [DEPRECATED] Resident Key
- Client-side discoverable Credential
-
注意:历史上,client-side discoverable credentials 曾被称为 resident credentials 或 resident keys。由于术语
ResidentKey与residentKey在 WebAuthn API 与 Authenticator Model(例如在字典成员名、算法变量名和操作参数中)被广泛使用,为了向后兼容,这些名称中的resident并未更改。此外,这里将 resident key 定义为等同于 client-side discoverable credential。Client-side discoverable Public Key Credential Source(简称 Discoverable Credential)是一个可被 authentication ceremonies 发现并用于认证的 public key credential source,适用于 Relying Party 不提供任何 credential ID 的情况,也就是 empty 的
allowCredentials参数被传入navigator.credentials.get()时。这意味着 Relying Party 不必事先识别用户。因此,一个支持 discoverable credential 的 authenticator 能够仅凭一个 RP ID 为一个 discoverable credential 生成 assertion signature,这要求相应的 public key credential source 被存储在认证器或 client platform 中。与之相对的 Server-side Public Key Credential Source 要求 authenticator 同时得到 RP ID 和 credential ID,但不要求在客户端侧存储该凭证源。
另见:client-side credential storage modality 与 non-discoverable credential。
注意:Client-side discoverable credentials 也可用于在 authentication ceremonies 中提供了 credential ID 的情况,即当调用
navigator.credentials.get()并传入非 empty 的allowCredentials参数时。 - Conforming User Agent
-
与底层的 client device 合作,实现 Web Authentication API 以及本规范中给出的算法,并处理 authenticators 与 Relying Parties 之间通信的用户代理。
- Credential ID
-
一个概率上唯一的 字节序列,用于识别 public key credential source 及其 authentication assertions。长度不超过 1023 字节。
Credential IDs 由 authenticators 以两种形式生成:
-
至少 16 字节且包含至少 100 位熵,或
-
对 public key credential source(去掉其 Credential ID 或 可变项)进行加密的形式,使得只有其 managing authenticator 能解密它。此形式使得认证器几乎无状态,依赖于 Relying Party 存储必要的状态。
注意:[FIDO-UAF-AUTHNR-CMDS] 在 “Security Guidelines” 中包含了关于加密技术的指导。
Relying Parties 无需区别这两种 Credential ID 形式。
-
- Credential
Key Pair
- Credential Private Key
- Credential Public Key
- User Public Key
- Credential Private Key
-
credential key pair 是由 authenticator 生成并且相对于特定 WebAuthn Relying Party 被 作用域化 的一对非对称加密密钥。它是 public key credential 的核心部分。
credential public key 是 credential key pair 的公钥部分。credential public key 在 registration ceremony 中返回给 Relying Party。
credential private key 是 credential key pair 的私钥部分。credential private key 被绑定到特定的 authenticator —— 即其 managing authenticator —— 并被期望永远不对任何其它方暴露,甚至不对认证器的拥有者暴露。
注意在 self attestation 的情况下,credential key pair 也被用作 attestation key pair,详见 self attestation 的说明。
注意:在 FIDO UAF 的 [UAFProtocol] 与 FIDO U2F 的 [FIDO-U2F-Message-Formats] 中,以及与之相关的本规范部分,credential public key 被称为 user public key。
- Credential Properties
-
credential property 是 public key credential source 的某些特征属性,例如它是否为 client-side discoverable credential 或 server-side credential。
- Credential Record
-
为了实现 § 7 WebAuthn Relying Party Operations 中定义的算法,Relying Party 必须存储已注册的 public key credential sources 的一些属性。credential record struct 是这些属性在 user account 中存储的抽象表示。credential record 在 registration ceremony 中创建,并在随后的 authentication ceremonies 中使用。Relying Parties 可以根据需要或应用户请求删除 credential records。
为了实现 § 7.1 注册新凭证 与 § 7.2 验证认证断言 的所有步骤,建议存储下列 items:
- type
- id
- publicKey
- signCount
- transports
-
当 公钥凭据源 被 注册 时,
getTransports()返回的值。注意: 修改或移除
getTransports()返回值中的 项目 可能会影响用户体验,甚至导致相应凭据无法使用。 - uvInitialized
-
一个布尔值,表示该 公钥凭据源 的任意 凭据 是否设置过 UV 标志。
当此值为
true时,服务接受方 可以在 认证仪式 中将 UV 标志 视为一种 认证因子。 例如,如 uvInitialized 为true并且 UV 标志已设置时,服务接受方 可以跳过密码提示,即便未要求 用户验证。当此值为
false时,包括某个 认证仪式 会将其变为true的情形, UV标志 不能作为 认证因子 依赖。 这是因为 公钥凭据源 第一次将 UV 标志 置为 1 时,服务接受方 与 认证器 的 用户验证 之间尚未建立信任关系。 因此,将 uvInitialized 从false更新为true时, 应当要求通过等同于 WebAuthn 用户验证 的额外 认证因子 进行授权。 - backupEligible
- backupState
下列 items 为可选项:
- attestationObject
-
在 公钥凭据源 被 注册 时,
attestationObject属性的值。 存储该值可以让 服务接受方 日后引用此凭据的 证明声明。 - attestationClientDataJSON
-
当该 public key credential source 被 registered 时,
clientDataJSON属性的值。将此值与上述的 attestationObject 一起存储,可使 Relying Party 在以后重新验证 attestation signature。
WebAuthn 扩展 可能定义处理该扩展所需的额外 items。Relying Parties 也可以根据需要包含任何额外的 items,并且可以省略其实现中不需要的任何 items。
用于凭证记录的 credential descriptor for a credential record 是一个具有下列内容的
PublicKeyCredentialDescriptor值:type-
该 credential record 的 type。
id-
该 credential record 的 id。
transports
- Generating Authenticator
-
Generating Authenticator 是参与导致创建给定 public key credential source 的 authenticatorMakeCredential 操作的认证器。对于 single-device credentials,生成认证器与该 managing authenticator 相同。对于 multi-device credentials,生成认证器可能与在某次 authentication 操作中参与的当前 managing authenticator 是否相同则不确定。
- Human Palatability
-
一个被称为 human-palatable 的标识符,旨在便于典型用户记忆和重复,与例如随机生成的比特序列不同,参见 [EduPersonObjectClassSpec]。
- Non-Discoverable Credential
-
指一种 credential,其 credential ID 必须在调用
navigator.credentials.get()时通过allowCredentials提供,因为它不可被 client-side discoverable。另见 server-side credentials。 - Registrable Origin Label
-
某域名的可注册域(registrable domain)的第一个 domain label,如果该可注册域为 null 则返回 null。例如,当
co.uk与de都是 public suffixes 时,example.co.uk与www.example.de的 registrable origin label 均为example。 - Public Key Credential
-
一般来说,凭据 是一个实体向另一个实体展示的数据,用于向后者 认证 前者的身份 [RFC4949]。术语 公钥凭据 可指以下之一:公钥凭据源、与 公钥凭据源 对应的、可能已经过证明的 凭据公钥,或是一次 认证断言。具体指哪一个通常取决于上下文。
注意:这在某种程度上是对 [RFC4949] 的一种“有意违反”。在英语中,“credential” 一词既可以表示用于证明的事物,也常被期望可被多次使用。在公钥系统中,用单一数据同时安全地满足这两点是不可能的。[RFC4949] 将 credential 定义为可以多次使用的事物(即公钥),而本规范在术语使用上更灵活。为避免歧义,本规范使用更具体的术语来标识与 [RFC4949] 中的 credential 相关的数据:- "Authentication information" (possibly including a private key)
- "Signed value"
- [RFC4949] "credential"
在 registration 时,authenticator 创建一个非对称密钥对,并将其 私钥部分 与来自 Relying Party 的信息存入一个 public key credential source。公钥部分 被返回给 Relying Party,随后由其存入该用户的活动 user account。随后,仅由用其注册时所用的 RP ID 标识的相同实体(即该 Relying Party)才能在 authentication ceremonies 中使用该 public key credential,通过
get()方法。Relying Party 使用其存储的 credential public key 来验证由该凭证产生的 authentication assertion。 - Public Key Credential Source
-
一个用于认证器生成 authentication assertions 的 credential source(参见 [CREDENTIAL-MANAGEMENT-1])。一个 public key credential source 由一个 struct 组成,其包含下列 items:
- type
-
其值为
PublicKeyCredentialType,默认值为public-key。 - id
-
一个 Credential ID。
- privateKey
- rpId
-
该 公钥凭据源 所 关联 的 服务接受方标识符,用于标识此 服务接受方。 该标识由
参数在rp.idcreate()操作中决定。 - userHandle
-
该 public key credential source 在创建时关联的 user handle。该 item 可为空,但对于 discoverable credentials 来说,user handle 必须被填充。
- otherUI
-
可选的其它信息,用于 authenticator 在其 UI 中显示。例如,这可能包含用户的
displayName。otherUI 是一个 mutable item,且不应以阻止该 public key credential source 更新其 otherUI 的方式进行绑定。
authenticatorMakeCredential 操作会创建一个绑定到 managing authenticator 的 public key credential source,并返回与其 credential private key 相关联的 credential public key。Relying Party 可使用该 credential public key 来验证由该 public key credential source 创建的 authentication assertions。
- Rate Limiting
-
通过限制在给定时间段内连续失败认证尝试次数来对抗暴力破解攻击的过程(亦称为节流)。若达到限制,认证器应对每次连续失败尝试施加指数增长的延迟,或禁用当前认证方式并在可用时提供另一个 authentication factor。Rate limiting 通常作为 user verification 的一部分实现。
- Registration
- Registration Ceremony
-
指的是在该 ceremony 中,用户、Relying Party 与用户的 client platform(包含或连接至少一个 authenticator)协同工作以创建 public key credential 并将其与 user account 关联。注意这包括使用 用户存在性测试 或 user verification。成功的 registration ceremony 后,用户可以通过 authentication ceremony 进行认证。
WebAuthn 的 registration ceremony 在 § 7.1 注册新凭证 中定义,由 Relying Party 调用带有
publicKey参数的操作来发起。参见 § 5 Web Authentication API 的介绍性概览和 § 1.3.1 注册 的实现示例。navigator.credentials.create() - Relying
Party
- WebAuthn Relying Party
-
其 web application 利用 Web Authentication API 来 注册 与 认证 用户的实体。
一个 Relying Party 实现通常由客户端脚本(在 client 中调用 Web Authentication API)和在服务器端执行 Relying Party 操作 及其它应用逻辑的组件共同组成。两部分之间的通信必须使用 HTTPS 或等效的传输安全,但除此之外超出本规范的范围。
注意:虽然 服务接受方(Relying Party) 这个术语在其他上下文(例如 X.509 和 OAuth)中也经常被使用,但在一个上下文中作为 服务接受方 的实体,在其他上下文中未必也是 服务接受方。在本规范中,WebAuthn 服务接受方 通常被简称为 服务接受方,并明确指 WebAuthn 上下文中的 服务接受方。需要注意的是,在任何具体实现中,WebAuthn 上下文可能被嵌入到更广泛的环境当中,例如基于 OAuth 的体系。
- Relying
Party Identifier
- RP ID
-
在 WebAuthn API 的上下文中,relying party identifier 是用来标识代表其执行某次注册或认证仪式的 WebAuthn Relying Party 的一个 valid domain string。一个 public key credential 只能与其注册时所用的相同实体(由 RP ID 标识)一起用于 authentication。
默认情况下,WebAuthn 操作的 RP ID 设置为调用者的 origin 的 effective domain。调用者可以覆盖该默认值,只要调用者指定的 RP ID 值 是 调用者 origin 的 effective domain 的可注册域后缀或与之相等。另见 § 5.1.3 Create a New Credential - PublicKeyCredential’s [[Create]](origin, options, sameOriginWithAncestors) Internal Method 与 § 5.1.4 Use an Existing Credential to Make an Assertion。
RP ID是基于主机的域名。它本身不包含协议或端口,而origin包含这些信息。 RP ID决定了公钥凭证的作用域。 即它决定公钥凭证可以被使用的 origin 集合,具体如下:
-
下列条件至少满足一个:
例如,若某 Relying Party 的 origin 为
https://login.example.com:1337,则合法的 RP ID 为login.example.com(默认)和example.com,但不包括m.login.example.com与com。另一个合法的 origin 示例为http://localhost:8000,因为 origin 为localhost。这样做是为了匹配广泛部署的环境凭证(例如 cookie,参见 [RFC6265])的行为。请注意,这比 document.domain 的 setter 提供的“同源”放宽程度更大。
这些对 origin 值的限制适用于 WebAuthn Clients。
其它旨在在非 Web 平台(例如原生移动应用)上启用 WebAuthn public key credentials 的规范,可能会为将调用者绑定到 Relying Party Identifier 定义不同的规则。但 RP ID 的语法必须符合 valid domain strings 或 URI(参见 [RFC3986] 与 [URL])。
- Server-side Public Key Credential Source
- Server-side Credential
- [DEPRECATED] Non-Resident Credential
- Server-side Credential
-
注意:历史上,server-side credentials 曾被称为 non-resident credentials。为向后兼容,本规范中包含 "resident" 的若干 WebAuthn API 与 Authenticator Model 组件名称并未更改。
Server-side Public Key Credential Source(简称 Server-side Credential)是一个仅在 authentication ceremony 中可用的 public key credential source,前提为 Relying Party 在
navigator.credentials.get()的allowCredentials参数中提供其 credential ID。这意味着 Relying Party 必须管理该凭证的存储与发现,并且必须能够先识别用户以便找出要在navigator.credentials.get()调用中提供的 credential IDs。对于 server-side credential,不要求在 client-side 存储 public key credential source。这与 client-side discoverable credential 不同,后者无需先识别用户就可以在
navigator.credentials.get()调用中提供用户的 credential ID 列表。另见:server-side credential storage modality 与 non-discoverable credential。
- Test of User Presence
-
test of user presence 是一种简单的 authorization gesture 与技术过程,用户通常通过简单地触碰认证器(也可能有其它方式)与认证器交互,从而得到布尔结果。注意这并不构成 user verification,因为用户存在性测试并不具备进行 生物识别识别 的能力,也不涉及诸如密码或 PIN 等共享秘密的呈现。
- User Account
-
在本规范中, 用户账户 指的是将一组 凭据 [CREDENTIAL-MANAGEMENT-1] 映射到 服务接受方 资源(或其子集)上的关系,并由 服务接受方 维护和授权。 服务接受方 通过为凭据的 用户句柄 分配一个特定于 用户账户 的值,并将该凭据的 凭据记录 存储在 用户账户 中,从而将某个 公钥凭据 映射到 用户账户。 这种映射、凭据集合及其授权可以随着时间变化。 一个 用户账户 可能由一个或多个自然人(即“用户”)访问, 一个自然人也可能根据其自身及 服务接受方 的操作访问一个或多个 用户账户。
- User Consent
-
用户同意意味着用户认同他们被请求的内容,即包含阅读并理解提示的要素。authorization gesture 常作为指示 user consent 的仪式组件。
- User Handle
-
用户句柄是用户账户的标识符,由服务接受方在user.id 作为参数,在注册时指定。可发现凭据会存储该标识符,并且在以空 allowCredentials 参数启动的认证仪式中,必须将其作为 response.userHandle 返回。
用户句柄的主要用途是在此类认证仪式中标识用户账户,但也可以使用凭据ID。主要区别在于,凭据ID由认证器选择,每个凭据唯一,而用户句柄由服务接受方选择,并且应对同一用户账户下所有注册的凭据保持一致。
认证器会映射 RP ID 和用户句柄的二元组到公钥凭据源。 因此,每个认证器对于每个服务接受方、每个用户句柄,最多只会存储一个可发现凭据。因此,用户句柄的另一个用处是,在注册仪式期间,允许认证器判断何时需要用新的可发现凭据替换已有的。
用户句柄是一个不透明的字节序列,最大长度为64字节,不应展示给用户。其内容不得包含任何个人身份信息,详见§ 14.6.1 用户句柄内容。
- User Present
- User Verification
-
一种技术过程,authenticator 在本地授权调用 authenticatorMakeCredential 与 authenticatorGetAssertion 操作。User verification 可以通过多种 authorization gesture 形式来实现,例如触摸加 PIN、密码输入,或 生物识别(例如指纹识别)。其目的在于区分不同的个体。另见 § 6.2.3 认证因子能力。
注意 user verification 并不会向 Relying Party 提供用户的具体身份,但当对同一 credential 已经执行了两次或更多次带有 user verification 的仪式时,它表明是同一用户执行了这些仪式。不过,如果多个自然人共享对同一 authenticator 的访问,则同一用户未必总是同一自然人。
注意:将自然人区分开在很大程度上依赖于 client platform 与 authenticator 的能力。例如,有些设备旨在单个个人使用,但它们可能允许多名自然人注册指纹或知道相同的 PIN,从而能使用该设备访问相同的 user account(s)。
注意:调用 authenticatorMakeCredential 和 authenticatorGetAssertion 操作意味着将使用认证器管理的密钥材料。
为保证安全,user verification 与使用 credential private keys 必须全部在定义 authenticator 的逻辑安全边界内发生。
User verification 程序可以实现 rate limiting 以防暴力破解攻击。
- User Verified
-
在成功完成 user verification 过程后,用户被称为 "verified"。
5. Web 身份验证 API
本节规范性地指定了用于创建和使用 公钥凭证 的 API。基本思路是凭证属于用户,并由 管理 它们的 WebAuthn 认证器 负责,WebAuthn 依赖方 通过 客户端平台 与其交互。Relying Party 的脚本可以在取得 用户同意 后,请求浏览器为将来由该 Relying Party 使用创建一个新的凭证。见下文的 图。
脚本也可以请求用户许可,以便对现有凭证执行 认证 操作。见下文的 图。
所有此类操作均在认证器内执行,并由 客户端平台 代表用户进行中介。脚本在任何时刻都不会直接获得凭证本身;它只会以对象的形式获取关于凭证的信息。
除了上述的脚本接口外,认证器可以实现(或随同会实现该功能的客户端软件一起提供)一个用于管理的用户界面。这样的界面可用于例如将认证器重置为初始状态或检查认证器的当前状态。换言之,这类界面类似于浏览器为管理用户状态(例如历史记录、已保存密码和 cookie)提供的用户界面。诸如删除凭证之类的认证器管理操作被视为此类用户界面的职责,并有意从暴露给脚本的 API 中省略。
该 API 的安全属性由客户端与认证器共同提供。持有并 管理 凭证的认证器保证所有操作都相对于特定的 origin 进行 作用域化,并通过在其响应中包含 origin 来确保这些响应不能被重放到不同的 origin。具体而言,如在 § 6.3 认证器操作 中所定义,请求者的完整 origin 会被包含并签名于当创建新凭证时产生的 attestation object,以及所有由 WebAuthn 凭证生成的断言中。
此外,为了维护用户隐私并防止恶意 Relying Parties 探测属于其它 Relying Parties 的 公钥凭证 的存在,每个 凭证 也被 作用域化 到一个 Relying Party 标识符(或称 RP ID)。此 RP ID 在所有操作中由客户端提供给 认证器,且 认证器 确保由某一 Relying Party 创建的 凭证 仅能在同一 RP ID 请求的操作中被使用。以这种方式将 origin 与 RP ID 分离,使得在单个 Relying Party 维护多个 origins 的情况下也能使用该 API。
客户端通过为每次操作向 认证器 提供 Relying Party 的 origin 与 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]]internal slot 中数据的 base64url 编码。 rawId-
此属性返回存储在
[[identifier]]内部槽中的ArrayBuffer。 response, of type AuthenticatorResponse, readonly-
此属性包含 认证器 对客户端请求创建 公钥凭证 或生成 认证断言 的响应。如果
PublicKeyCredential是响应create()创建的, 该属性的值将为AuthenticatorAttestationResponse; 否则, 若PublicKeyCredential是响应get()创建的, 则该属性的值将为AuthenticatorAssertionResponse。 authenticatorAttachment, of type DOMString, readonly, nullable-
此属性报告在
navigator.credentials.create()或navigator.credentials.get()方法成功完成时生效的 认证器附着方式。 属性值应当为AuthenticatorAttachment的一个成员。 Relying Parties 应将未知值视为 null。注意:如果在一次 注册 或 认证仪式 的结果中,authenticatorAttachment的值为 "cross-platform" 并且同时isUserVerifyingPlatformAuthenticatorAvailable返回true,则说明用户在当次 仪式 中使用了一个 漫游认证器,同时存在可用的 平台认证器。因此 Relying Party 有机会提示用户注册可用的 平台认证器,以便启用更顺畅的用户体验流程。认证器的 attachment modality 可能随时间变化。例如,某些手机起初可能只支持 平台附着,但随后通过更新也支持 跨平台附着。
getClientExtensionResults()-
此操作返回
[[clientExtensionsResults]]的值, 它是一个包含扩展的 映射,映射条目为 扩展标识符 → 客户端扩展输出,这些条目由扩展的 客户端扩展处理 产生。 isConditionalMediationAvailable()-
PublicKeyCredential重写此方法以指示在conditional介入下navigator.credentials.get()可用。WebAuthn 服务接受方 在尝试将options.设置为mediationconditional之前应当验证功能是否可用。调用该方法时,会返回一个 Promise,如果
conditional用户介入 可用,则解析为true,否则为false。此方法无参数,返回一个 Promise,Promise 的值为布尔值。
conditionalGet功能等效于此 Promise 解析为true。注意:如果没有此方法,则
conditional用户介入 不可用于navigator.credentials.get()。注意:此方法 不 表示
conditional用户介入 在navigator.credentials.create()中是否可用。 如需判断,请参阅conditionalCreate能力以及getClientCapabilities()。 toJSON()-
此操作返回
RegistrationResponseJSON或AuthenticationResponseJSON, 它们是反映PublicKeyCredential的 JSON 类型 表示,适合作为application/json有效负载提交给 Relying Party 服务器。客户端 负责像往常那样将值序列化为 JSON 类型,但必须采取额外步骤:先将任何ArrayBuffer值编码为DOMString值,方法是使用 base64url 编码。成员
RegistrationResponseJSON.clientExtensionResults或AuthenticationResponseJSON.clientExtensionResults必须设置为getClientExtensionResults()的输出,其中任何ArrayBuffer值都必须使用 base64url 编码 转为DOMString。这可以包括来自 IANA “WebAuthn Extension Identifiers” 注册表中注册但未在 § 9 WebAuthn 扩展 定义的扩展中返回的ArrayBuffer值。成员
AuthenticatorAttestationResponseJSON.transports必须设置为getTransports()的输出。成员
AuthenticatorAttestationResponseJSON.publicKey必须设置为getPublicKey()的输出。成员
AuthenticatorAttestationResponseJSON.publicKeyAlgorithm必须设置为getPublicKeyAlgorithm()的输出。
typedef DOMString ; // The structure of this object will be either // RegistrationResponseJSON or 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 >; // The publicKey field will be missing if pubKeyCredParams was used to // negotiate a public-key algorithm that the user agent doesn't // understand. (See section “Easily accessing credential data” for a // list of which algorithms user agents must support.) If using such an // algorithm then the public key must be parsed directly from // attestationObject or authenticatorData.transports Base64URLString ;publicKey required COSEAlgorithmIdentifier ; // This value contains copies of some of the fields above. See // section “Easily accessing credential data”.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]]-
The
PublicKeyCredential接口对象’s[[type]]内部槽’s value is the string "public-key".注意: 这一点通过从
type属性 getter(继承自Credential)体现出来。 [[discovery]]-
The
PublicKeyCredential接口对象’s[[discovery]]内部槽’s value is "remote". [[identifier]]-
This 内部槽包含由认证器选择的credential ID。 该 credential ID 用于查找并使用凭证,因此预计在相同类型的所有凭证以及所有认证器之间具有很高概率的全局唯一性。
此 API 不限制该标识符的格式,唯一的要求是其长度 不得超过 1023 字节,并且必须足以让authenticator 唯一地选择一个密钥。 例如,没有板载存储的认证器可能会创建包含被对称密钥包裹的credential private key 的标识符,该对称密钥被烧录到认证器中。
[[clientExtensionsResults]]-
This 内部槽包含在 Relying Party 调用以下任一方法时,请求的客户端扩展处理结果:
navigator.credentials.create()或navigator.credentials.get()。
PublicKeyCredential
的
接口对象继承了 Credential
对 [[CollectFromCredentialStore]](origin, options, sameOriginWithAncestors)
的实现,
并为以下每个方法定义了自己的实现:[[Create]](origin, options, sameOriginWithAncestors)、
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
和
[[Store]](credential, sameOriginWithAncestors)。
调用 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.
Create a New Credential - PublicKeyCredential’s [[Create]](origin, options, sameOriginWithAncestors)
Internal Method
PublicKeyCredential
的
interface object 对 [[Create]](origin, options, sameOriginWithAncestors)
内部方法 的实现(见
[CREDENTIAL-MANAGEMENT-1])允许 WebAuthn Relying Party 脚本
调用 navigator.credentials.create()
来请求创建一个绑定到某个 authenticator
的新的 public key credential source、bound 的凭证。
通过将
options.
设为 mediationconditional,
Relying Parties
可以表明如果用户已同意创建凭证,则希望在不显示显著模态 UI 的情况下注册凭证。
Relying Party 应先使用 getClientCapabilities()
检查 client 是否支持 conditionalCreate
功能,以避免在该功能不可用时出现面向用户的错误。
当
options.
被设置为 mediationconditional
时,客户端必须将 requireUserPresence 和 requireUserVerification 都设置为
FALSE,除非这些项可以在仪式期间显式执行。
任何 navigator.credentials.create()
操作都可以通过利用 AbortController
被中止;详见 DOM § 3.3 使用
AbortController 和 AbortSignal 对象 获取详细说明。
此内部方法接受三个参数:
origin-
此参数是由调用
create()实现确定的相关设置对象(relevant settings object)的 origin。 options-
此参数是一个
CredentialCreationOptions对象,其options.成员包含一个publicKeyPublicKeyCredentialCreationOptions对象,用以指定待创建的 public key credential 的期望属性。 sameOriginWithAncestors-
此参数是一个布尔值,当且仅当调用者的 environment settings object 与其祖先同源(same-origin with its ancestors)时为
true。如果调用者为跨源,则为false。注意: 调用此内部方法 表示该操作已被 permissions policy 允许,该权限策略在 [CREDENTIAL-MANAGEMENT-1] 级别进行评估。参见 § 5.9 Permissions Policy integration。
注意: 该算法为同步执行: Promise
的解析/拒绝由 navigator.credentials.create()
负责。
在此算法中使用的所有 BufferSource
对象必须在算法开始时进行快照,以避免潜在的同步问题。实现应当 获取缓冲源所持字节的副本 并在算法相关部分使用该副本。
当此方法被调用时,用户代理必须执行下列算法:
-
断言:
options.存在。publicKey -
如果 sameOriginWithAncestors 为
false:-
如果
options.存在且值为mediationconditional:-
抛出一个 "
NotAllowedError"DOMException
-
-
如果调用
create()的实现所确定的相关全局对象(relevant global object)不具有 瞬时激活(transient activation):-
抛出一个 "
NotAllowedError"DOMException。
-
-
对相关全局对象执行 Consume user activation 操作。
-
如果创建凭证的 origin 与相关全局对象的顶层 origin(top-level origin)不同(即与用户在地址栏看到的 origin 不同), 则 client 应向用户明确说明此事实。
-
-
令 pkOptions 为
options.的值。publicKey -
如果
pkOptions.存在,则检查其值是否在由 client 定义的合理范围内;若不在,则修正为最接近且位于该范围内的值。将定时器 lifetimeTimer 设为此调整后值。如果timeoutpkOptions.不存在,则将 lifetimeTimer 设为 client-特定的默认值。timeout关于为
pkOptions.决定合理范围和值的指导,请参阅 推荐范围和默认值。timeoutclient 应在为有特殊需要的用户考虑超时时采用认知方面的指导原则。
-
令 callerOrigin 为
origin。 如果 callerOrigin 为 opaque origin,则抛出一个 "NotAllowedError"DOMException。 -
令 effectiveDomain 为 callerOrigin 的 effective domain。 如果该 effective domain 不是一个 valid domain,则抛出一个 "
SecurityError"DOMException。注意: 一个 effective domain 可能解析为一个 host,而 host 可以以多种方式表示,例如 domain、ipv4 address、ipv6 address、opaque host 或 empty host。 此处仅允许 domain 格式的表示。这样做既为简化,也考虑到在与基于 PKI 的安全结合使用时直接使用 IP 地址识别所带来的各种问题。
-
- 存在
-
如果
pkOptions.不是 effectiveDomain 的可注册域后缀且与其不相等,且客户端rp.id- 支持 related origin requests
-
-
使用参数 callerOrigin 和 rpIdRequested 运行 related origins validation procedure。如果结果为
false,则抛出一个 "SecurityError"DOMException。
- 不支持 related origin requests
-
抛出一个 "
SecurityError"DOMException。
- 不存在
注意:
pkOptions.表示调用者的 RP ID。除非调用者在调用rp.idcreate()时明确设置了pkOptions.,否则 RP ID 默认为调用者的 origin 的 effective domain。rp.id -
令 credTypesAndPubKeyAlgs 为一个新的列表,该列表的条目为
PublicKeyCredentialType与COSEAlgorithmIdentifier的配对。 -
如果
pkOptions.的 大小pubKeyCredParams- 为零
-
Append 下列
PublicKeyCredentialType与COSEAlgorithmIdentifier配对添加到 credTypesAndPubKeyAlgs:-
public-key与-7("ES256")。 -
public-key与-257("RS256")。
-
- 非零
-
对
pkOptions.的每个项 current 执行下列操作:pubKeyCredParams-
如果
current.不包含此实现所支持的typePublicKeyCredentialType, 则 继续下一个项。 -
令 alg 为
current.。alg
如果 credTypesAndPubKeyAlgs 为空,则抛出一个 "
NotSupportedError"DOMException。 -
-
令 clientExtensions 为一个新的 map,并令 authenticatorExtensions 为一个新的 map。
-
如果
pkOptions.存在,则对extensionspkOptions.中的每个 extensionId → clientExtensionInput 执行下列操作:extensions-
如果 extensionId 不被此 client platform 支持,或不是一个 registration extension,则 继续下一个扩展。
-
将 clientExtensions[extensionId] 设置为 clientExtensionInput。
-
如果 extensionId 不是一个 authenticator extension,则 继续下一个扩展。
-
令 authenticatorExtensionInput 为对 clientExtensionInput 运行该 extensionId 的 client extension processing 算法后得到的(CBOR)结果。如果该算法返回错误,则 继续下一个扩展。
-
将 authenticatorExtensions[extensionId] 设置为 authenticatorExtensionInput 的 base64url 编码。
-
-
令 collectedClientData 为一个新的
CollectedClientData实例,其字段为:type-
字符串 "webauthn.create"。
challenge-
pkOptions.
challenge的 base64url 编码。 origin-
callerOrigin 的 序列化表示。
crossOrigin-
此值为传入此内部方法 的参数
sameOriginWithAncestors的值的反值(inverse)。 topOrigin-
如果传入的
sameOriginWithAncestors参数为false,则为 callerOrigin 的顶层 origin 的 序列化表示,否则为undefined。
-
令 clientDataJSON 为由 collectedClientData 构造的 与 JSON 兼容的客户端数据序列化。
-
令 clientDataHash 为由 clientDataJSON 表示的序列化客户端数据的哈希,参见 说明。
-
如果
options.存在且 已中止(aborted),则抛出该signalsignal的 中止原因(abort reason)。 -
令 issuedRequests 为新的 有序集合(ordered set)。
-
令 authenticators 表示一个值,该值在任一时刻为一个有序集合,其中的每个项标识在该时刻此 client platform 上当前可用的一个 authenticator 的本地句柄(handle)。
注意: 何谓“可用的”authenticator 未作具体规定;这旨在表示 authenticators 可通过多种机制被 client 热插拔(hot-plug,如 USB)或被发现(如 NFC 或蓝牙),或永久内置于 client 中。
-
如果
options.存在且值为mediationconditional:-
如果用户代理最近没有进行过调停的认证、所述认证的来源不是 callerOrigin,或用户不同意此类凭证创建,则抛出一个 "
NotAllowedError"DOMException。由用户代理决定何时认为某次认证仪式已完成。该认证仪式可以通过 Web Authentication API 之外的其它方式完成。
-
-
根据
hints的值并由用户代理酌情设计用户界面。 -
启动 lifetimeTimer。
-
当
lifetimeTimer 未到期时,根据 lifetimeTimer 以及 authenticators 中每个
authenticator 的状态与响应,执行下列操作:
- 如果 lifetimeTimer 到期,
-
对 issuedRequests 中的每个 authenticator 调用 authenticatorCancel 操作,并将该 authenticator 从 issuedRequests 中移除。
- 如果用户在用户代理 UI 中选择取消该过程,
-
对 issuedRequests 中的每个 authenticator 调用 authenticatorCancel 操作,并从 issuedRequests 中移除该 authenticator。然后抛出一个 "
NotAllowedError"DOMException。 - 如果
options.存在且 已中止,signal -
对 issuedRequests 中的每个 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。然后抛出该
signal的中止原因(abort reason)。 - 如果某个 authenticator 在此 client device 上变为可用,
-
注意: 这也包括在启动 lifetimeTimer 时认证器已可用的情况。
-
该 authenticator 现在为 候选认证器(candidate authenticator)。
-
如果
pkOptions.存在:authenticatorSelection-
如果
pkOptions.存在且其值与该 authenticator 的 attachment modality 不符,则 继续(跳过此认证器)。authenticatorSelection.authenticatorAttachment -
如果
pkOptions.authenticatorSelection.residentKey- 若存在且设为
required -
如果该 authenticator 无法存储一个 client-side discoverable public key credential source,则 继续(跳过此认证器)。
- 若存在且设为
preferred或discouraged -
无影响。
- 若不存在
-
如果
pkOptions.被设置为authenticatorSelection.requireResidentKeytrue且该 authenticator 无法存储 client-side discoverable public key credential source,则 继续(跳过此认证器)。
- 若存在且设为
-
如果
pkOptions.被设置为authenticatorSelection.userVerificationrequired且该 authenticator 无法执行 user verification,则 继续(跳过此认证器)。
-
-
令 requireResidentKey 为 用于凭证创建的有效 resident key 要求,为布尔值,按如下规则决定:
如果
pkOptions.authenticatorSelection.residentKey- 存在且设为
required -
令 requireResidentKey 为
true。 - 存在且设为
preferred -
如果该 authenticator
- 支持 client-side credential storage modality
-
令 requireResidentKey 为
true。 - 不支持 client-side credential storage modality,或客户端无法确定认证器能力,
-
令 requireResidentKey 为
false。
- 存在且设为
discouraged -
令 requireResidentKey 为
false。 - 不存在
-
令 requireResidentKey 为
pkOptions.的值。authenticatorSelection.requireResidentKey
- 存在且设为
-
令 userVerification 为 用于凭证创建的有效 user verification 要求,为布尔值,按如下规则决定。如果
pkOptions.authenticatorSelection.userVerification- 设为
required -
-
如果
options.被设置为mediationconditional且在仪式期间无法收集到 user verification,则抛出一个ConstraintErrorDOMException。 -
令 userVerification 为
true。
-
- 设为
preferred -
如果该 authenticator
- 能够执行 user verification
-
令 userVerification 为
true。 - 不能执行 user verification
-
令 userVerification 为
false。
- 设为
discouraged -
令 userVerification 为
false。
- 设为
-
令 enterpriseAttestationPossible 为布尔值,如下决定。如果
pkOptions.attestation- 被设为
enterprise -
如果用户代理希望为
pkOptions.支持企业级 attestation(参见步骤 8),则令 enterpriseAttestationPossible 为rp.idtrue,否则为false。 - 其它情况
-
令 enterpriseAttestationPossible 为
false。
- 被设为
-
令 attestationFormats 为一个字符串列表,其初始值为
pkOptions.的值。attestationFormats -
如果
pkOptions.attestation- 被设为
none -
将 attestationFormats 设为仅包含字符串 “none” 的单元素列表。
- 被设为
-
令 excludeCredentialDescriptorList 为一个新的 列表。
-
对
pkOptions.中的每个凭证描述符 C 执行:excludeCredentials-
如果
C.非空,且该 authenticator 是通过一个不在transportsC.列表中的传输方式连接的,则客户端可以选择 继续(跳过)。transports注意: 若客户端选择 继续,这可能导致在同一认证器上意外注册多个绑定到同一 bound 的凭证,如果存储的传输提示(transports)并不准确。例如,软件升级可能添加新的连接选项,从而使先前存储的传输提示变得不准确。
-
否则,将 C 追加 到 excludeCredentialDescriptorList。
-
- 在该 authenticator 上调用 authenticatorMakeCredential 操作,参数为
clientDataHash、
pkOptions.、rppkOptions.、 requireResidentKey、userVerification、 credTypesAndPubKeyAlgs、excludeCredentialDescriptorList、 enterpriseAttestationPossible、attestationFormats 和 authenticatorExtensions。user -
将该 authenticator 追加 到 issuedRequests。
-
- 如果某个 authenticator 在此 client device 上不再可用,
-
从 issuedRequests 中 移除 该 authenticator。
- 如果任何 authenticator 返回表示用户取消操作的状态,
-
-
从 issuedRequests 中 移除 该 authenticator。
-
对 issuedRequests 中的每个剩余 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。
注意: Authenticators 可能返回一个指示“用户取消了整个操作”的状态。用户代理如何向用户呈现该状态未在本规范中规定。
-
- 如果任何 authenticator 返回等同于 "
InvalidStateError" 的错误状态, -
-
从 issuedRequests 中 移除 该 authenticator。
-
对 issuedRequests 中的每个剩余 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。
-
抛出一个 "
InvalidStateError"DOMException。
注意: 该错误状态单独处理的原因在于,authenticator 仅在 excludeCredentialDescriptorList 标识了绑定到该 authenticator 的凭证且用户已对该操作表示了 同意 时才返回此错误。鉴于此明确同意,将此情况向 Relying Party 区分是可接受的。
-
- 如果任何 authenticator 返回的错误状态不等同于 "
InvalidStateError", -
从 issuedRequests 中 移除 该 authenticator。
注意: 该情况并不意味着对该操作存在 用户同意,因此为避免泄露可能识别用户的信息,有关错误的详情会对 Relying Party 隐藏。详见 § 14.5.1 Registration Ceremony Privacy。
- 如果任何 authenticator 指示成功,
-
-
将该 authenticator 从 issuedRequests 中 移除。该认证器现在为 选定认证器(selected authenticator)。
-
令 credentialCreationData 为一个 struct,其 items 包括:
-
attestationObjectResult -
其值为从成功的 authenticatorMakeCredential 操作返回的字节。
注意: 此值即在 § 6.5.4 Generating an Attestation Object 中定义的
attObj。 -
clientDataJSONResult -
其值为 clientDataJSON 的字节。
-
attestationConveyancePreferenceOption -
其值为 pkOptions.
attestation的值。 -
clientExtensionResults -
其值为一个
AuthenticationExtensionsClientOutputs对象,包含 扩展标识符 → 客户端扩展输出 的条目。这些条目是对pkOptions.中的每个客户端扩展运行其 client extension processing 算法以创建对应的客户端扩展输出而生成的。extensions
-
-
令 constructCredentialAlg 为一个算法,该算法接受一个全局对象 global,其步骤如下:
-
如果
credentialCreationData.attestationConveyancePreferenceOption的值为:none-
用非识别性(non-identifying)版本替换可能具有唯一识别性的字段:
-
如果 attested credential data 中的 aaguid 为 16 个零字节, 并且
credentialCreationData.attestationObjectResult.fmt为 "packed",且"x5c"在credentialCreationData.attestationObjectResult中缺失, 则正在使用 self attestation,无需进一步操作。 -
否则:
-
将
credentialCreationData.attestationObjectResult.fmt的值设为 "none",并将credentialCreationData.attestationObjectResult.attStmt的值设为一个空的 CBOR map。(参见 § 8.7 None Attestation Statement Format 与 § 6.5.4 Generating an Attestation Object)。
-
-
indirect-
客户端可以用更有利于隐私或更易验证的版本替换 aaguid 与 attestation statement(例如,采用 Anonymization CA)。
direct或enterprise-
不作修改地将认证器的 AAGUID 及 attestation statement 传送给 Relying Party。
-
令 attestationObject 为新的
ArrayBuffer, 使用 global 的 %ArrayBuffer% 创建, 包含credentialCreationData.attestationObjectResult的字节。 -
令 id 为
attestationObject.authData.attestedCredentialData.credentialId。 -
令 pubKeyCred 为新的
PublicKeyCredential对象(与 global 关联),其字段为:[[identifier]]-
id
authenticatorAttachment-
与该 authenticator 当前 attachment modality 相匹配的
AuthenticatorAttachment值。 response-
一个新的与 global 关联的
AuthenticatorAttestationResponse对象,其字段为:clientDataJSON-
一个新的
ArrayBuffer, 使用 global 的 %ArrayBuffer% 构造方法创建,内容为credentialCreationData.clientDataJSONResult的字节。 attestationObject-
attestationObject
[[transports]]-
一个按字典序排列的不重复
DOMString序列,表示认为 authenticator 支持的传输方式。 这些值应属于AuthenticatorTransport, 但客户端平台必须忽略未知值。如果用户代理不希望泄露此信息,则可以用任意设计用于保护隐私的序列替代。该序列仍必须有效,即按字典序排序且无重复项。例如可使用空序列。不论如何,这种情况下用户代理需承担服务接受方行为不佳的风险。
如果用户代理没有任何传输信息,应将该字段设为空序列。
注意:用户代理如何发现某个认证器支持的传输方式,超出本规范范围,但可包括来自 证明证书(如 [FIDO-Transports-Ext])、CTAP2 等 认证器 协议中的元数据或针对某些平台认证器的特殊知识。
[[clientExtensionsResults]]-
一个新的
ArrayBuffer, 使用 global 的 %ArrayBuffer% 创建, 包含credentialCreationData.clientExtensionResults的字节。
-
返回 pubKeyCred。
-
-
对 issuedRequests 中的每个剩余 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。
-
返回 constructCredentialAlg 并终止该算法。
-
-
抛出一个 "
NotAllowedError"DOMException。
在上述过程中,用户代理应向用户显示某些 UI 以指导其选择并授权认证器。当
options.
被设置为 mediationconditional
时,
除非凭证创建已通过用户代理确定的手段先前获得同意,否则不应显示显著的模态 UI。
5.1.3.1. Create Request Exceptions
本节为非规范性说明。
WebAuthn Relying
Parties 可能在调用 navigator.credentials.create()
时遇到若干异常。某些异常可能由多种原因导致,
WebAuthn
Relying Parties 需要结合它们对 WebAuthn 的使用来推断实际原因。
注意: 在处理任何 WebAuthn 扩展(包括本规范之外定义的扩展)时可能引发的异常并未在此列出。
下列 DOMException
异常可能被抛出:
AbortError-
该仪式被
AbortController取消。 参见 § 5.6 使用 AbortSignal 中止操作 和 § 1.3.4 中止认证操作 示例。 ConstraintError-
要么
residentKey被设置为required且没有可用的认证器支持驻留密钥;要么userVerification被设置为required且没有可用的认证器能够执行 user verification。 InvalidStateError-
用于本次仪式的认证器在用户已对注册凭证表示 同意 后识别出
excludeCredentials中的某个条目。 NotSupportedError-
pubKeyCredParams中没有条目的type属性为public-key, 或者该 authenticator 不支持pubKeyCredParams中指定的任何签名算法。 SecurityError-
effective domain 不是一个 有效域名, 或者
并非等于或不是 effective domain 的可注册域后缀。 在后者情况下,client 不支持 related origin requests 或 related origins validation procedure 校验失败。rp.id NotAllowedError-
一个涵盖多种可能原因的通用错误,包括常见情况例如用户取消了该仪式。 本规范中有些原因在各处已有记录,另一些原因则与客户端实现相关。
下列 simple exceptions 也可能被抛出:
TypeError-
options参数不是一个有效的CredentialCreationOptions值,或者的值为空或长于 64 字节。user.id
5.1.4. Use an Existing Credential to Make an Assertion
WebAuthn Relying
Parties 调用
navigator.credentials.get({publicKey:..., ...})
以发现并使用现有的 public
key credential,并取得用户的 同意。Relying Party 脚本可选择性地指定一些条件来表明哪些 public key credential
sources 对其是可接受的。client platform 会定位满足指定条件的 public key credential
sources,并指导用户选择一个脚本被允许使用的凭证。用户也可能选择拒绝整个交互,即使存在 public key credential
source,例如为了维护隐私。如果用户选择了一个 public key credential source,用户代理随后使用 § 6.3.3 The authenticatorGetAssertion Operation 将 Relying Party 提供的
challenge 和其它收集的数据签名成一个 authentication assertion,该断言被用作一个 credential。
navigator.credentials.get()
的实现(见 [CREDENTIAL-MANAGEMENT-1])会调用
PublicKeyCredential.
来收集任何应可在无 用户调停(大致对应本规范的 authorization gesture)情况下可用的 credentials,如果未找到恰好一个这样的凭证,则调用
[[CollectFromCredentialStore]]()PublicKeyCredential.
以让用户选择一个 public key credential source。
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
鉴于本规范要求为创建任何 assertions 提供 authorization
gesture,PublicKeyCredential
继承了 [[CollectFromCredentialStore]](origin, options, sameOriginWithAncestors)
的默认行为,即返回空集合。PublicKeyCredential
对 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
的实现在下一节中说明。
通常,用户代理应向用户显示一些 UI 以指导其在选择并授权认证器以完成操作时的交互。通过将
options.
设为 mediationconditional,
Relying Parties
可以表明在未发现凭证时不应显示显著的模态 UI,除非确实发现了凭证。
Relying Party 应先使用 isConditionalMediationAvailable()
或 getClientCapabilities()
检查 client 是否支持 conditionalGet
功能,以避免在该功能不可用时产生面向用户的错误。
任何 navigator.credentials.get()
操作都可以通过使用 AbortController
被中止;
详见 DOM § 3.3 使用
AbortController 和 AbortSignal 对象在 API 中的整合 获取详细说明。
5.1.4.1. PublicKeyCredential’s
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
Internal Method
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)该内部方法接受三个参数:
origin-
该参数是由调用
get()实现确定的相关设置对象(relevant settings object) 的 origin,即CredentialsContainer的 Request aCredential抽象操作所确定的 origin。 options-
该参数是一个
CredentialRequestOptions对象,其options.成员包含一个publicKeyPublicKeyCredentialRequestOptions对象,用于指定要发现的 public key credential 的期望属性。 sameOriginWithAncestors-
该参数为布尔值,当且仅当调用者的 environment settings object 与其祖先同源(same-origin with its ancestors)时为
true。如果调用者为跨源,则为false。注意: 调用此内部方法 表示该操作已被permissions policy 允许,该权限策略在 [CREDENTIAL-MANAGEMENT-1] 级别进行评估。参见 § 5.9 Permissions Policy integration。
注意: 该算法为同步执行: Promise
的解析/拒绝由 navigator.credentials.get()
负责。
在此算法中使用的所有 BufferSource
对象必须在算法开始时进行快照,以避免潜在的同步问题。实现应当 获取缓冲源所持字节的副本 并在算法相关部分使用该副本。
当此方法被调用时,用户代理必须执行下列算法:
-
断言:
options.存在。publicKey -
令 pkOptions 为
options.的值。publicKey -
如果
options.存在且值为mediationconditional:-
令 credentialIdFilter 为
pkOptions.的值。allowCredentials -
将
pkOptions.设为 空。allowCredentials注意: 这样可以防止在
conditional请求期间使用 non-discoverable credentials。 -
将定时器 lifetimeTimer 设为无穷大。
注意: 将 lifetimeTimer 设为无穷大,是为了让用户在整个 Document 的生命周期内与任何带有
"webauthn"autofill detail token 的input表单控件进行交互。例如,当用户点击此类输入字段时,用户代理可以渲染已发现凭证的列表供用户选择,并可能提供“尝试其他方式”的选项。
-
-
否则:
-
令 callerOrigin 为
origin。 如果 callerOrigin 为 opaque origin,则抛出一个 "NotAllowedError"DOMException。 -
令 effectiveDomain 为 callerOrigin 的 effective domain。 如果该 effective domain 不是一个 有效域名,则抛出一个 "
SecurityError"DOMException。注意: 一个 effective domain 可能解析为一个 host,而 host 可以以多种方式表示,例如 domain、ipv4 address、ipv6 address、opaque host 或 empty host。 此处仅允许 domain 格式的表示。这样做既为简化,也考虑到在与基于 PKI 的安全结合使用时直接使用 IP 地址识别所带来的各种问题。
-
如果
pkOptions.rpId- 存在
-
如果
pkOptions.不是 effectiveDomain 的可注册域后缀且与其不相等,且客户端支持:rpId- 支持 related origin requests
-
-
令 rpIdRequested 为
pkOptions.的值。rpId -
使用参数 callerOrigin 和 rpIdRequested 运行 related origins validation procedure。如果结果为
false,则抛出一个 "SecurityError"DOMException。
-
- 不支持 related origin requests
-
抛出一个 "
SecurityError"DOMException。
- 不存在
-
将
pkOptions.设为 effectiveDomain。rpId
注意: rpId 表示调用者的 RP ID。除非调用者在调用
get()时明确设置了pkOptions.,否则 RP ID 默认为调用者的 origin 的 origin 的 effective domain。rpId -
令 clientExtensions 为一个新的 map,并令 authenticatorExtensions 为一个新的 map。
-
如果
pkOptions.存在,则对extensionspkOptions.中的每个 extensionId → clientExtensionInput 执行:extensions-
如果 extensionId 不被此 client platform 支持,或不是一个 authentication extension,则 继续下一个扩展。
-
Set clientExtensions[extensionId] 为 clientExtensionInput。
-
如果 extensionId 不是一个 authenticator extension,则 继续下一个扩展。
-
令 authenticatorExtensionInput 为对 clientExtensionInput 运行该 extensionId 的 client extension processing 算法后得到的(CBOR)结果。如果该算法返回错误,则 继续下一个扩展。
-
Set authenticatorExtensions[extensionId] 为 authenticatorExtensionInput 的 base64url 编码。
-
-
令 collectedClientData 为一个新的
CollectedClientData实例,其字段为:type-
字符串 "webauthn.get"。
challenge-
pkOptions.
challenge的 base64url 编码。 origin-
callerOrigin 的 序列化表示。
crossOrigin-
此值为传入此内部方法 的参数
sameOriginWithAncestors的反值(inverse)。 topOrigin-
如果传入的
sameOriginWithAncestors参数为false,则为 callerOrigin 的顶层 origin 的 序列化表示,否则为undefined。
-
令 clientDataJSON 为由 collectedClientData 构造的 与 JSON 兼容的客户端数据序列化。
-
令 clientDataHash 为由 clientDataJSON 表示的序列化客户端数据的哈希,参见 说明。
-
如果
options.存在且 已中止(aborted),则抛出该signalsignal的中止原因(abort reason)。 -
令 issuedRequests 为一个新的 有序集合(ordered set)。
-
令 savedCredentialIds 为一个新的 map。
-
令 authenticators 表示一个值,该值在任一时刻为一个有序集合,其中每个项标识在该时刻此 client platform 上当前可用的一个 authenticator 的本地句柄。
注意: 何谓“可用的”认证器未作具体规定;这旨在表示认证器可以通过多种机制被热插拔(hot-plug,例如 USB)或被发现(例如 NFC 或蓝牙),或永久内置于客户端。
-
令 silentlyDiscoveredCredentials 为一个新的 map,其 条目 形式为:DiscoverableCredentialMetadata → authenticator。
-
根据
hints的值并由用户代理酌情设计用户界面。 -
启动 lifetimeTimer。
-
当 lifetimeTimer 未到期时,基于 lifetimeTimer 以及 authenticators 中每个 authenticator 的状态与响应,执行下列操作:
- 如果 lifetimeTimer 到期,
-
对 issuedRequests 中的每个 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。
- 如果用户在用户代理 UI 中选择取消该过程,
-
对 issuedRequests 中的每个 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。抛出一个 "
NotAllowedError"DOMException。 - 如果
options.存在且 已中止,signal -
对 issuedRequests 中的每个 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。然后抛出该
signal的中止原因(abort reason)。 - 如果
options.为mediationconditional且用户与带有input或textarea表单控件交互, 且该控件具有autocomplete属性,其 non-autofill credential type 为"webauthn", -
注意:
"webauthn"的 autofill detail token 必须紧接在最后一个类型为 "Normal" 或 "Contact" 的 autofill detail token 之后。例子:-
"username webauthn" -
"current-password webauthn"
-
如果 silentlyDiscoveredCredentials 非 空:
-
提示用户可选地从 silentlyDiscoveredCredentials 中选择一个 DiscoverableCredentialMetadata。 提示应当展示每个 DiscoverableCredentialMetadata 的 otherUI 中的值,例如
name和displayName。令 credentialMetadata 为用户选择的 DiscoverableCredentialMetadata,如果用户有选择的话。
-
如果用户选择了一个 credentialMetadata,
-
令 publicKeyOptions 为 pkOptions 的临时副本。
-
令 authenticator 为 silentlyDiscoveredCredentials[credentialMetadata] 的值。
-
将
publicKeyOptions.设为包含单个allowCredentialsPublicKeyCredentialDescriptor项的 list,该项的id值设为 credentialMetadata 的 id 的值,且其id值设为 credentialMetadata 的 type。 -
对 authenticator 执行 issuing a credential request to an authenticator 算法,参数为 authenticator、savedCredentialIds、publicKeyOptions、rpId、clientDataHash 和 authenticatorExtensions。
如果该调用返回
false,则 继续(跳过该认证器)。 -
Append authenticator 到 issuedRequests。
-
-
-
- 如果
options.不是mediationconditional, 且 issuedRequests 为空,pkOptions.非空, 且其中没有任何 authenticator 将可用于任何其中列出的 public key credentials,allowCredentials -
向用户指示未找到合格凭证。当用户确认对话框后,抛出一个 "
NotAllowedError"DOMException。注意: 客户端平台可以通过检查当前
pkOptions.中每个allowCredentialsPublicKeyCredentialDescriptor项的transports成员来判断没有认证器会变得可用。例如,如果所有项仅列出PublicKeyCredentialDescriptor,但所有平台认证器(platform authenticators)都已被尝试,则不存在满足请求的可能性。或者,所有internal项可能列出了客户端平台不支持的PublicKeyCredentialDescriptor。transports - 如果某个 authenticator 在此 client device 上变为可用,
-
注意: 这也包括在启动 lifetimeTimer 时认证器已可用的情况。
-
如果
options.为mediationconditional且该 authenticator 支持 silentCredentialDiscovery 操作:-
令 collectedDiscoveredCredentialMetadata 为对该 authenticator 执行 silentCredentialDiscovery 操作(以 rpId 为参数) 的结果。
-
对 collectedDiscoveredCredentialMetadata 中的每个 credentialMetadata:
-
-
否则:
-
执行 issuing a credential request to an authenticator 算法,参数为 authenticator、savedCredentialIds、pkOptions、rpId、clientDataHash 和 authenticatorExtensions。
如果该调用返回
false,则 继续(跳过该认证器)。注意: 如果
options.为mediationconditional且该 authenticator 不支持 silentCredentialDiscovery,则会走到此分支以允许在conditional的 user mediation 请求中使用此类认证器。 -
Append authenticator 到 issuedRequests。
-
-
- 如果某个 authenticator 在此 client device 上不再可用,
-
从 issuedRequests 中 移除 该 authenticator。
- 如果任何 authenticator 返回表示用户取消操作的状态,
-
-
从 issuedRequests 中 移除 该 authenticator。
-
对 issuedRequests 中的每个剩余 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。
注意: 认证器可能返回“用户取消了整个操作”的指示,用户代理如何向用户呈现该状态未作规定。
-
- 如果任何 authenticator 返回错误状态,
-
从 issuedRequests 中 移除 该 authenticator。
- 如果任何 authenticator 指示成功,
-
-
从 issuedRequests 中 移除 该 authenticator。
-
令 assertionCreationData 为一个 struct,其 items 如下:
-
credentialIdResult -
如果
savedCredentialIds[authenticator]存在,则将 credentialIdResult 的值设为savedCredentialIds[authenticator]的字节。否则,将其值设为在成功的 authenticatorGetAssertion 操作中返回的 credential ID 的字节(详见 § 6.3.3)。 -
clientDataJSONResult -
其值为 clientDataJSON 的字节。
-
authenticatorDataResult -
其值为该 authenticator 返回的 authenticator data 的字节。
-
signatureResult -
其值为该 authenticator 返回的签名值的字节。
-
userHandleResult -
如果该 authenticator 返回了 user handle,则将 userHandleResult 的值设为返回的 user handle 的字节。否则,将其设为 null。
-
clientExtensionResults -
其值为一个
AuthenticationExtensionsClientOutputs对象,包含 扩展标识符 → 客户端扩展输出 的条目。这些条目是对pkOptions.中的每个客户端扩展运行其 client extension processing 算法以创建对应的客户端扩展输出而生成的。extensions
-
-
如果 credentialIdFilter 非空且 credentialIdFilter 不包含一个项,其
id的值等于 credentialIdResult 的值,则 继续(跳过该认证器)。 -
如果 credentialIdFilter 为空且 userHandleResult 为 null,则 继续(跳过该认证器)。
-
令 settings 为当前的 settings object。令 global 为 settings 的 global object。
-
令 pubKeyCred 为与 global 关联的新
PublicKeyCredential对象,其字段为:[[identifier]]-
一个新的
ArrayBuffer, 使用 global 的 %ArrayBuffer% 创建,包含assertionCreationData.credentialIdResult的字节。 authenticatorAttachment-
与该 authenticator 当前 attachment modality 相匹配的
AuthenticatorAttachment值。 response-
一个新的与 global 关联的
AuthenticatorAssertionResponse对象,其字段为:clientDataJSON-
一个新的
ArrayBuffer, 使用 global 的 %ArrayBuffer% 创建,包含assertionCreationData.clientDataJSONResult的字节。 authenticatorData-
一个新的
ArrayBuffer, 使用 global 的 %ArrayBuffer% 创建,包含assertionCreationData.authenticatorDataResult的字节。 signature-
一个新的
ArrayBuffer, 使用 global 的 %ArrayBuffer% 创建,包含assertionCreationData.signatureResult的字节。 userHandle-
如果
assertionCreationData.userHandleResult为 null,则将此字段设为 null。否则,将此字段设为一个新的ArrayBuffer, 使用 global 的 %ArrayBuffer% 创建,包含assertionCreationData.userHandleResult的字节。
[[clientExtensionsResults]]-
一个新的
ArrayBuffer, 使用 global 的 %ArrayBuffer% 创建,包含assertionCreationData.clientExtensionResults的字节。
-
对 issuedRequests 中的每个剩余 authenticator 调用 authenticatorCancel 并将其从 issuedRequests 中移除。
-
返回 pubKeyCred 并终止该算法。
-
-
抛出一个 "
NotAllowedError"DOMException。
5.1.4.2. 向 Authenticator 发出凭证请求
此子算法属于 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors),
包含了在给定的 credential 请求中,针对特定但与 UI 上下文无关的步骤,这些步骤用于向某个指定的 authenticator 请求凭证,所使用的是给定的
PublicKeyCredentialRequestOptions。
它由 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
从不同点调用,具体取决于当前的 user mediation(例如:conditional
mediation)的限制。
此算法接受下列参数:
authenticator-
一个特定于 client platform 的句柄,用于标识当前在该 client platform 上可用的某个 authenticator。
savedCredentialIds-
一个 map,其中包含 authenticator → credential ID 的映射。此参数将在本算法中被修改。
pkOptions-
该参数是一个
PublicKeyCredentialRequestOptions对象,用以指定要发现的 public key credential 的期望属性。 rpId-
请求的 RP ID。
clientDataHash-
由 clientDataJSON 表示的序列化客户端数据的哈希,参见 说明。
authenticatorExtensions-
一个 map,其中包含 extension identifiers 到 base64url 编码 的映射, 这些值是为 authenticator extensions 产生的 client extension processing 输出的编码结果。
如果 client 判定该 authenticator
无法处理该请求,则此算法返回 false;如果请求成功下发,则返回 true。
下列为 向 Authenticator 发出凭证请求 的步骤:
-
如果
pkOptions.被设置为userVerificationrequired且该 authenticator 无法执行 user verification,则返回false。 -
令 userVerification 为 用于断言的有效用户验证要求,这是一个布尔值,按如下规则决定。如果
pkOptions.userVerification- 被设为
required -
令 userVerification 为
true。 - 被设为
preferred -
如果该 authenticator
- 能够执行 user verification
-
令 userVerification 为
true。 - 不能执行 user verification
-
令 userVerification 为
false。
- 被设为
discouraged -
令 userVerification 为
false。
- 被设为
-
如果
pkOptions.allowCredentials- 不为空
-
-
令 allowCredentialDescriptorList 为一个新的 列表。
-
执行一个 client platform 专用的过程,以决定
pkOptions.所描述的哪些(如果有)public key credentials 是绑定(bound)到当前 authenticator 的,通过匹配 rpId、allowCredentialspkOptions.和allowCredentials.idpkOptions.。 将 allowCredentialDescriptorList 设为此过滤后的列表。allowCredentials.type -
如果 allowCredentialDescriptorList 为空,则返回
false。 -
令 distinctTransports 为一个新的 有序集合。
-
如果 allowCredentialDescriptorList 恰好只有一个值,则将
savedCredentialIds[authenticator]设为allowCredentialDescriptorList[0].id的值(详见 此处,见 § 6.3.3)。 -
对于 allowCredentialDescriptorList 中的每个凭证描述符 C,追加
C.中的每个值(如果有)到 distinctTransports。transports注意: 由于 有序集合 的特性,这将仅聚合该 authenticator 的不同
transports值到 distinctTransports 中。 -
如果 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。
注意: 在此情形下,Relying Party 未提供可接受的凭证描述符列表。因此,authenticator 被要求使用其可能拥有的、并且作用域(scoped)到该 Relying Party(由 rpId 标识)的任何凭证。
-
返回
true。
5.1.4.3. Get Request Exceptions
本节为非规范性说明。
WebAuthn Relying
Parties 在调用 navigator.credentials.get()
时可能会遇到若干异常。
某些异常可能由多种原因引起,WebAuthn Relying Parties 需要结合它们对 WebAuthn 的使用来推断实际原因。
注意: 在处理任何 WebAuthn 扩展(包括本规范之外定义的扩展)时可能引发的异常并未在此列出。
下列 DOMException
异常可能被抛出:
AbortError-
该流程被
AbortController取消。 参见 § 5.6 使用 AbortSignal 中止操作 和 § 1.3.4 中止认证操作 示例。 SecurityError-
effective domain 不是一个 有效域名, 或者
并非等于或不是 effective domain 的可注册域后缀。 在后者情况下,client 不支持 related origin requests 或 related origins validation procedure 校验失败。rp.id NotAllowedError-
一个涵盖多种可能原因的通用错误,包括常见情形例如用户取消该流程。 本规范中有些原因在各处已有记录,另一些原因与客户端实现相关。
下列 simple exceptions 也可能被抛出:
TypeError-
options参数不是一个有效的CredentialRequestOptions值。
5.1.5. 存储现有凭证 - PublicKeyCredential 的
[[Store]](credential, sameOriginWithAncestors) 内部方法
对于 Web Authentication 的 PublicKeyCredential
类型,[[Store]](credential, sameOriginWithAncestors)
方法不受支持,因此其实现的 [[Store]](credential, sameOriginWithAncestors)
内部方法 总是抛出错误。
注意: 此算法为同步执行;Promise
的解析/拒绝由 navigator.credentials.store()
处理。
该内部方法接受两个参数:
credential-
此参数为一个
PublicKeyCredential对象。 sameOriginWithAncestors-
此参数为布尔值,当且仅当调用者的 environment settings object 与其祖先同源(same-origin with its ancestors)时为
true。
当此方法被调用时,用户代理必须执行下列算法:
-
抛出一个 "
NotSupportedError"DOMException。
5.1.6. User-Verifying Platform Authenticator 的可用性 -
PublicKeyCredential 的 isUserVerifyingPlatformAuthenticatorAvailable() 方法
WebAuthn
Relying Parties 使用此方法来判断是否可以使用 user-verifying platform authenticator
来创建新凭证。
在调用时,client 将通过特定于 client
platform 的过程去发现可用的 user-verifying platform authenticators。
如果发现了任一此类设备,则返回的 promise 会以 true 解析,否则以 false 解析。
基于该结果,Relying Party
可采取进一步措施引导用户创建凭证。
此方法无参数,返回一个布尔值。
partial interface PublicKeyCredential {static Promise <boolean >(); };isUserVerifyingPlatformAuthenticatorAvailable
注意: 从一个被 browsing context 调用此方法时,如果据 Web Authentication API 的
"allowed to use" 算法判断该 API 在该上下文被“禁用”,——即受 permissions policy 的约束——则返回的 promise
会被拒绝,拒绝原因为名为 "NotAllowedError"
的 DOMException。
另请参阅 § 5.9 Permissions Policy integration。
5.1.7.
Client 能力的可用性 - PublicKeyCredential 的 getClientCapabilities()
方法
WebAuthn
Relying Parties 使用此方法来判断一组有限的 client 能力是否可用,从而为用户提供某些工作流或体验。例如,在某些客户端上仅当存在 hybrid
传输可用或 conditional
mediation 不可用时(而不是显示用户名字段),RP 可能会在页面上提供一个登录按钮。
在调用时,client 通过特定于 client platform 的过程来发现这些能力的可用性。
此方法无参数,返回一个将能力键映射到布尔值的记录(record)。
partial interface PublicKeyCredential {static Promise <PublicKeyCredentialClientCapabilities >(); };getClientCapabilities typedef record <DOMString ,boolean >;PublicKeyCredentialClientCapabilities
PublicKeyCredentialClientCapabilities 中的键(Keys)必须按升序字典序排序。
键集合应包含 枚举值 集合(即 ClientCapability
的值),但客户端可按需省略某些键;见 § 14.5.4 披露客户端能力。
当某项能力的值为 true 时,表示该功能已知当前被客户端支持。
当某项能力的值为 false 时,表示该功能已知当前不被客户端支持。
当某项能力作为键不存在时,该客户端功能的可用性未知(unknown)。
该键集合还应为客户端实现的每个扩展包含一个键,键的形式为在扩展标识符前加上字符串 extension:。对于每个实现的扩展,其对应值应为
true。如果某个客户端支持 getClientCapabilities(),但未将某扩展映射为 true,则 Relying Party
可以假定该客户端不会执行该扩展的客户端处理步骤,并且该扩展可能不会转发给 authenticator。
注意即便某扩展映射为 true,用于某次操作的 authenticator 也可能不支持该扩展,因此 Relying Parties 不得仅据此假定 authenticator
会执行该扩展的处理步骤。
注意: 从一个被 browsing context 调用此方法时,如果据 Web Authentication API 的
"allowed to use" 算法判断该 API 在该上下文被“禁用”,——即受 permissions policy 的约束——则返回的 promise
会被拒绝,拒绝原因为名为 "NotAllowedError"
的 DOMException。
另请参阅 § 5.9 Permissions Policy integration。
5.1.8.
反序列化注册流程选项 - PublicKeyCredential 的 parseCreationOptionsFromJSON()
方法
WebAuthn
Relying Parties 使用此方法将用于 navigator.credentials.create()
的选项的 JSON 表示转换为 PublicKeyCredentialCreationOptions。
在调用时,client 必须将 options
参数转换为一个新的、结构相同的 PublicKeyCredentialCreationOptions
对象,
并使用 base64url 编码
解码出现在 DOMString
属性中对应于 PublicKeyCredentialCreationOptionsJSON
的那些值,这些值对应于 PublicKeyCredentialCreationOptions
中的 buffer source 类型属性。
该转换也必须应用于任何由 client extension inputs 所处理的扩展。
AuthenticationExtensionsClientInputsJSON
可能包括在 IANA “WebAuthn Extension Identifiers” 注册表中注册但未在本规范(§ 9 WebAuthn
Extensions)中定义的扩展。
如果 client 在解析任何 JSON 表示时遇到问题,则必须抛出一个
"EncodingError"
的 DOMException,并附带不兼容值的描述,然后终止操作。
partial interface PublicKeyCredential {static PublicKeyCredentialCreationOptions (parseCreationOptionsFromJSON PublicKeyCredentialCreationOptionsJSON ); };options dictionary {PublicKeyCredentialCreationOptionsJSON required PublicKeyCredentialRpEntity ;rp required PublicKeyCredentialUserEntityJSON ;user required Base64URLString ;challenge required sequence <PublicKeyCredentialParameters >;pubKeyCredParams unsigned long ;timeout sequence <PublicKeyCredentialDescriptorJSON >= [];excludeCredentials AuthenticatorSelectionCriteria ;authenticatorSelection sequence <DOMString >= [];hints DOMString = "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
Relying Parties 使用此方法将用于 navigator.credentials.get()
的选项的 JSON 表示转换为 PublicKeyCredentialRequestOptions。
在调用时,client 必须将 options
参数转换为一个新的、结构相同的 PublicKeyCredentialRequestOptions
对象,
并使用 base64url 编码
解码出现在 DOMString
属性中对应于 PublicKeyCredentialRequestOptionsJSON
的那些值,这些值对应于 PublicKeyCredentialRequestOptions
中的 buffer source 类型属性。
该转换也必须应用于任何由 client extension inputs 所处理的扩展。
AuthenticationExtensionsClientInputsJSON
可能包括在 IANA “WebAuthn Extension Identifiers” 注册表中注册但未在本规范(§ 9 WebAuthn
Extensions)中定义的扩展。
如果 client 在解析任何 JSON 表示时遇到问题,则必须抛出一个
"EncodingError"
的 DOMException,并附带不兼容值的描述,然后终止操作。
partial interface PublicKeyCredential {static PublicKeyCredentialRequestOptions (parseRequestOptionsFromJSON PublicKeyCredentialRequestOptionsJSON ); };options dictionary {PublicKeyCredentialRequestOptionsJSON required Base64URLString ;challenge unsigned long ;timeout DOMString ;rpId sequence <PublicKeyCredentialDescriptorJSON >= [];allowCredentials DOMString = "preferred";userVerification sequence <DOMString >= [];hints AuthenticationExtensionsClientInputsJSON ; };extensions
5.1.10. 向 Authenticator 发出凭证变更信号 - PublicKeyCredential 的 signal methods
partial interface PublicKeyCredential {static Promise <undefined >(signalUnknownCredential UnknownCredentialOptions );options static Promise <undefined >(signalAllAcceptedCredentials AllAcceptedCredentialsOptions );options static Promise <undefined >(signalCurrentUserDetails CurrentUserDetailsOptions ); };options dictionary {UnknownCredentialOptions required DOMString ;rpId required Base64URLString ; };credentialId dictionary {AllAcceptedCredentialsOptions required DOMString ;rpId required Base64URLString ;userId required sequence <Base64URLString >; };allAcceptedCredentialIds dictionary {CurrentUserDetailsOptions required DOMString ;rpId required Base64URLString ;userId required DOMString ;name required DOMString ; };displayName
WebAuthn Relying
Parties 可以使用这些 signal
methods 去通知 authenticators 有关 public key credentials 的状态,以便不正确或已撤销的凭证可以被更新、移除或隐藏。Clients 根据机会提供该功能,因为 authenticator
可能不支持更新其 credentials map,或者在请求发出时并未连接。此外,为避免在未取得 用户同意 的情况下泄露有关用户凭证的信息,signal methods
不会指示操作是否成功。一个成功解析的 promise 仅表示 options 对象格式正确。
每个 signal method 包含 authenticator actions。Authenticators 可以在其 authenticator actions 上与本规范偏离,例如忽略某些它合理地认为与用户意愿相悖的更改,或在做出某些更改前询问用户。因此,Authenticator actions 被作为处理 signal methods 的推荐方式。
在某些情况下,如果某个 authenticator
无能力处理某项 authenticator action,clients 可以选择使用现有基础设施(例如 [FIDO-CTAP] 的
authenticatorCredentialManagement 命令)来实现等效效果。
注意: Signal methods 故意避免等待 authenticators 完成执行 authenticator actions。此举旨在防止 WebAuthn Relying Parties 依据请求的时间信息在未取得 用户同意 的情况下得知其凭证是否可用,从而泄露隐私。
5.1.10.1. 异步 RP ID 验证算法
异步 RP ID 验证算法 允许 signal
methods 并行地验证 RP IDs。该算法接受一个 DOMString
参数 rpId 并返回一个 promise;如果验证失败则该 promise 被拒绝。步骤如下:
-
令 effectiveDomain 为相关设置对象(relevant settings object)的 origin 的 effective domain。如果 effectiveDomain 不是 有效域名,则返回 以 "
SecurityError" 命名的拒绝的 promise(即一个DOMException)。 -
如果 rpId 是 effectiveDomain 的可注册域后缀或与其相等,则返回 解析为 undefined 的 promise。
-
如果客户端不支持 related origin requests,则返回以 "
SecurityError" 命名的被拒绝的 promise。 -
令 p 为一个新的 promise。
-
并行执行下列步骤:
-
如果对 callerOrigin 与 rpId 运行 related origins validation procedure 的结果为
true,则 解析 p。 -
否则,拒绝 p,拒绝原因为 "
SecurityError" 的DOMException。
-
-
返回 p。
5.1.10.2. signalUnknownCredential(options)
signalUnknownCredential
方法用于向 WebAuthn
Relying Party 发出某个 credential id 未被识别的信号,例如因为该凭证被用户删除。与 signalAllAcceptedCredentials(options)
不同,此方法不需要传递整个被接受的 credential
IDs 列表及 userHandle,从而避免向未认证的调用者泄露隐私(参见 § 14.6.3 通过 credential IDs 的隐私泄露)。
在调用 signalUnknownCredential(options)
时,
client 执行下列步骤:
-
如果对
options.进行 base64url 解码 的结果是错误,则返回以一个credentialIdTypeError为原因被拒绝的 promise。 -
令 p 为以
options.为参数执行 异步 RP ID 验证算法 的结果。rpId -
在 p 成功后,按并行方式运行下列步骤:
-
对当前在该 client platform 上可用的每个 authenticator,调用 unknownCredentialId authenticator action,并以 options 作为输入。
-
-
返回 p。
unknownCredentialId authenticator action 接受一个 UnknownCredentialOptions
options 并按如下进行:
-
对该 authenticator 的 credential map 中的每个 public key credential source credential:
-
如果该 credential 的 rpId 等于
options.并且该 credential 的 id 等于对rpIdoptions.进行的 base64url 解码 的结果, 则从该 credentials map 中 移除该 credential,或使用某个 authenticator-专用的过程将其隐藏以防止其在将来的 authentication ceremonies 中出现。credentialId
-
用户在凭据的WebAuthn 依赖方提供的界面上删除了凭据。之后,当尝试使用WebAuthn 依赖方进行身份验证,且allowCredentials为空时,
认证器界面提供了他们之前删除的凭据作为选项。用户选择了该凭据。在拒绝本次登录尝试后,WebAuthn 依赖方执行如下操作:
PublicKeyCredential. signalUnknownCredential({ rpId: "example.com" , credentialId: "aabbcc" // credential id the user just tried, base64url });
然后 authenticator 将该 credential 从将来的 authentication ceremonies 中删除或隐藏。
5.1.10.3. signalAllAcceptedCredentials(options)
为给定用户发出其全部 credential ids
列表的信号。WebAuthn
Relying Parties 应在用户已完成身份验证且不存在隐私泄露风险时,优先使用此方法而非 signalUnknownCredential()(参见
§ 14.6.3 通过 credential IDs
的隐私泄露),因为该列表提供了用户的公钥凭证的完整快照,且可能反映尚未报告给当前已连接 authenticator 的更改。
在调用 signalAllAcceptedCredentials(options)
时,
client 执行下列步骤:
-
如果对
options.进行 base64url 解码 的结果是错误,则返回以userIdTypeError为原因被拒绝的 promise。 -
对于
options.中的每个 credentialId:allAcceptedCredentialIds-
如果对该 credentialId 进行 base64url 解码 的结果是错误,则返回以
TypeError为原因被拒绝的 promise。
-
-
令 p 为以
options.为参数执行 异步 RP ID 验证算法 的结果。rpId -
在 p 成功后,并行运行下列步骤:
-
对当前在该 client platform 上可用的每个 authenticator,调用 allAcceptedCredentialIds authenticator action,并以 options 作为输入。
-
-
返回 p。
名为 allAcceptedCredentialIds 的 authenticator actions 接受一个 AllAcceptedCredentialsOptions
options,其步骤如下:
-
令 userId 为对
options.进行的 base64url 解码 的结果。userId -
断言:userId 不是错误。
-
令 credential 为
credentials map[options.。rpId, userId] -
如果 credential 不存在,则中止这些步骤。
-
如果
options.不包含对该 credential 的 id 进行的 base64url 编码 的结果,则从 credentials map 中移除该 credential,或使用某个 authenticator-专用的过程将其隐藏以防止其在将来的 authentication ceremonies 中出现。allAcceptedCredentialIds -
否则,如果该 credential 已被某个 authenticator-专用过程隐藏,则撤销该隐藏操作,使该 credential 在将来的 authentication ceremonies 中重新可见。
某用户有两个凭证,其 credential ids
base64url 编码后为 aa 与 bb。用户在 WebAuthn Relying Party 提供的
UI 上删除了凭证 aa。该 WebAuthn Relying Party 运行:
PublicKeyCredential. signalAllAcceptedCredentials({ rpId: "example.com" , userId: "aabbcc" , // user handle, base64url. allAcceptedCredentialIds: [ "bb" , ] });
如果该 authenticator
在执行时已连接,它会删除或隐藏对应于 aa 的 credential,以免其在将来的认证流程中出现。
注意: 在调用 signalAllAcceptedCredentials(options)
时,Authenticators 可能未连接。因此,WebAuthn
Relying Parties 可能选择周期性地运行 signalAllAcceptedCredentials(options),例如在每次登录时。
注意: 未包含在 allAcceptedCredentialIds
中的凭证将被移除或隐藏,可能是不可逆的。Relying
parties 必须谨慎,确保有效的凭证 ID 永远不会被遗漏。如果某个有效的 credential ID 被意外遗漏,Relying Party 应尽快在下次有机会时通过 signalAllAcceptedCredentials(options)
将其包含回列表中,以便在 authenticator 支持的情况下将其“取消隐藏”。
Authenticators 应尽可能选择将公钥凭证在一段时间内隐藏,而不是永久删除,以便在 WebAuthn Relying Party 意外遗漏有效的 credential IDs 时便于恢复。
5.1.10.4. signalCurrentUserDetails(options)
signalCurrentUserDetails
方法用于发出用户当前的 name
和 displayName
的信号。
在调用 signalCurrentUserDetails(options)
时,
client 执行下列步骤:
-
如果对
options.进行 base64url 解码 的结果为错误,则返回以userIdTypeError为原因被拒绝的 promise。 -
令 p 为以
options.为参数执行 异步 RP ID 验证算法 的结果。rpId -
在 p 成功后,并行运行下列步骤:
-
对当前在该 client platform 上可用的每个 authenticator,调用 currentUserDetails authenticator action,并以 options 作为输入。
-
-
返回 p。
名为 currentUserDetails 的 authenticator action 接受一个 CurrentUserDetailsOptions
options,其步骤如下:
-
令 userId 为对
options.进行的 base64url 解码 的结果。userId -
断言:userId 不是错误。
-
令 credential 为
credentials map[options.。rpId, userId] -
如果 credential 不存在,则中止这些步骤。
-
将该 credential 的 otherUI 更新为与
options.和nameoptions.相匹配的值。displayName
用户在 WebAuthn Relying Party 提供的 UI 上更新了其姓名。该 WebAuthn Relying Party 运行:
PublicKeyCredential. signalCurrentUserDetails({ rpId: "example.com" , userId: "aabbcc" , // user handle, base64url. name: "New user name" , displayName: "New display name" });
然后 authenticator 更新匹配凭证的 otherUI 信息。
注意: Authenticators 可能在执行 signalCurrentUserDetails(options)
时未连接。因此,WebAuthn Relying Parties 可能选择定期运行 signalCurrentUserDetails(options),例如在每次登录时。
5.2.
Authenticator Responses (interface AuthenticatorResponse)
认证器 通过返回一个派生自 AuthenticatorResponse
接口的对象来响应 Relying Party 的请求:
[SecureContext ,Exposed =Window ]interface AuthenticatorResponse { [SameObject ]readonly attribute ArrayBuffer clientDataJSON ; };
clientDataJSON, of type ArrayBuffer, readonly-
该属性包含了 与 JSON 兼容的序列化 的 客户端数据,其 哈希值 由客户端在调用
create()或get()时传递给认证器(即客户端数据本身并不直接发送给认证器)。
5.2.1. Information About Public Key Credential (interface
AuthenticatorAttestationResponse)
The AuthenticatorAttestationResponse
接口表示认证器对客户端请求创建新 公钥凭证 的响应。它包含有关新凭证的信息,这些信息可用于
在以后识别该凭证,并且包含用于让 WebAuthn 依赖方
在注册期间评估该凭证特性的元数据。
[SecureContext ,Exposed =Window ]interface AuthenticatorAttestationResponse :AuthenticatorResponse { [SameObject ]readonly attribute ArrayBuffer attestationObject ;sequence <DOMString >();getTransports ArrayBuffer ();getAuthenticatorData ArrayBuffer ?();getPublicKey COSEAlgorithmIdentifier (); };getPublicKeyAlgorithm
clientDataJSON-
该属性继承自
AuthenticatorResponse, 包含了传递给认证器以生成该凭证的 与 JSON 兼容的客户端数据序列化(见 § 6.5 Attestation)。 必须保留精确的 JSON 序列化形式,因为对序列化的客户端数据所计算的 哈希 就是基于该序列化结果计算的。 attestationObject, of type ArrayBuffer, readonly-
该属性包含一个 attestation object,其对客户端是不透明的,并受到加密保护以防客户端篡改。attestation object 同时包含 authenticator data 和一个 attestation statement。 前者包含 AAGUID、唯一的 credential ID 以及 credential public key。 attestation statement 的内容由认证器使用的 attestation statement format 决定。 它还包含了 Relying Party 的服务器在验证 attestation statement 时所需的任何额外信息,以及用于解码和验证 authenticator data 与客户端数据的 JSON 兼容序列化 的信息。更多细节见 § 6.5 Attestation、§ 6.5.4 Generating an Attestation Object 与 图 6。
getTransports()-
此操作返回
[[transports]]的值。 getAuthenticatorData()-
此操作返回包含在
attestationObject中的 authenticator data。参见 § 5.2.1.1 Easily accessing credential data。 getPublicKey()-
此操作返回新凭证的 DER 格式的 SubjectPublicKeyInfo,如果不可用则返回 null。参见 § 5.2.1.1 Easily accessing credential data。
getPublicKeyAlgorithm()-
此操作返回新凭证的
COSEAlgorithmIdentifier。参见 § 5.2.1.1 Easily accessing credential data。 [[transports]]-
该内部槽 包含按字典序排列的零个或多个唯一
DOMString。这些值表示认为认证器支持的传输方式,若信息不可用则为一个空序列。值应当是AuthenticatorTransport的成员,但 Relying Parties 应接受并存储未知值。
5.2.1.1. Easily accessing credential data
每个使用 [[Create]](origin, options, sameOriginWithAncestors)
方法的用户都需要解析并存储返回的 credential public key,以便验证将来的 authentication
assertions。然而,credential public key 采用 COSE 格式(见 [RFC9052]),位于 credentialPublicKey 成员中,该成员属 attestedCredentialData,而 attestedCredentialData 位于 authenticator data
内,进而位于 attestation
object(由 AuthenticatorAttestationResponse
传递) 的 attestationObject
中。
希望使用 attestation 的 Relying Parties 必须自己解析
attestationObject
并取得 credential
public key,因为该公钥副本就是认证器所签名的。然而,许多有效的 WebAuthn 用例并不需要 attestation。对于这些用例,用户代理可以完成解析工作,直接暴露 authenticator
data,并将 credential public key 转换为更便于使用的格式。
因此,getPublicKey()
操作返回 credential
public key 的 SubjectPublicKeyInfo。该 ArrayBuffer
例如可以传递给 Java 的 java.security.spec.X509EncodedKeySpec、.NET 的
System.Security.Cryptography.ECDsa.ImportSubjectPublicKeyInfo 或 Go 的
crypto/x509.ParsePKIXPublicKey。
使用 getPublicKey()
会带来一些限制:通过使用 pubKeyCredParams,
Relying Party 可以与 authenticator
协商使用用户代理可能不理解的公钥算法。然而,如果 Relying
Party 这样做,用户代理将无法把得到的 credential public key 转换为 SubjectPublicKeyInfo 格式,此时 getPublicKey()
的返回值将为 null。
当 credential
public key 的 COSEAlgorithmIdentifier
值为下列之一时,用户代理必须能够为 getPublicKey()
返回非空值:
一个 SubjectPublicKeyInfo 并不包含关于签名算法(例如应使用哪种哈希函数)的信息,而这些信息在 COSE
公钥中包含。为了解决这个问题,getPublicKeyAlgorithm()
返回该 credential
public key 所对应的 COSEAlgorithmIdentifier。
为了在许多情况下无需解析 CBOR,getAuthenticatorData()
返回 attestationObject
中的 authenticator
data。authenticator data 包含其他以二进制格式编码的字段。但没有提供访问这些子字段的辅助函数,因为 Relying Parties 在获取断言(getting an assertion)时就已经需要提取这些字段。与凭证创建(credential creation)中签名验证为可选不同,Relying Parties
在断言中应始终验证签名,因此必须从签名的 authenticator data 中提取字段。用于那里的相同函数也会在凭证创建期间使用。
Relying Parties
在使用这些函数之前应做功能检测,方法是测试 'getPublicKey' in AuthenticatorAttestationResponse.prototype 的值。
注意: getPublicKey()
和 getAuthenticatorData()
仅在本规范的 Level 2 中新增。依赖这些函数存在的 Relying Parties 可能无法与较旧的用户代理互操作。
5.2.2. Web Authentication Assertion (interface AuthenticatorAssertionResponse)
The AuthenticatorAssertionResponse
接口表示认证器对客户端请求生成新的 authentication assertion 的响应,基于 WebAuthn 依赖方 的 challenge
以及可选的已知凭证列表。该响应包含一个证明持有 credential private key 的加密签名,并可选地包含对特定事务的 用户同意 的证据。
[SecureContext ,Exposed =Window ]interface AuthenticatorAssertionResponse :AuthenticatorResponse { [SameObject ]readonly attribute ArrayBuffer authenticatorData ; [SameObject ]readonly attribute ArrayBuffer signature ; [SameObject ]readonly attribute ArrayBuffer ?userHandle ; };
clientDataJSON-
该属性继承自
AuthenticatorResponse, 包含了传递给认证器以生成该断言的 与 JSON 兼容的客户端数据序列化(见 § 5.8.1 Client Data Used in WebAuthn Signatures (dictionary CollectedClientData))。 必须保留精确的 JSON 序列化形式,因为对序列化的客户端数据所计算的 哈希 就是基于该序列化结果计算的。 authenticatorData, of type ArrayBuffer, readonly-
该属性包含认证器返回的 authenticator data。参见 § 6.1 Authenticator Data。
signature, of type ArrayBuffer, readonly-
该属性包含认证器返回的原始签名。参见 § 6.3.3 The authenticatorGetAssertion Operation。
userHandle, of type ArrayBuffer, readonly, nullable-
该属性包含认证器返回的 user handle,如果认证器未返回 user handle,则为 null。参见 § 6.3.3 The authenticatorGetAssertion Operation。如果在 authentication ceremony 中使用的
allowCredentials选项为空列表(empty),则认证器必须始终返回一个 user handle;在其他情况下认证器可以选择返回或不返回。
5.3.
Parameters for Credential Generation (dictionary PublicKeyCredentialParameters)
dictionary PublicKeyCredentialParameters {required DOMString type ;required COSEAlgorithmIdentifier alg ; };
type, of type DOMString-
该成员指定将被创建的凭证类型。其值应当是
PublicKeyCredentialType的成员,但 client platforms 必须忽略未知值,忽略任何具有未知type的PublicKeyCredentialParameters。 alg, of type COSEAlgorithmIdentifier-
该成员指定用于新生成凭证的加密签名算法类型,从而也决定要生成的非对称密钥对的类型,例如 RSA 或 椭圆曲线。
注意: 我们使用 "alg" 作为成员名,而不是完整拼写 "algorithm",是因为它会被序列化到发往认证器的消息中,该消息可能通过低带宽链路发送。
5.4.
Options for Credential Creation (dictionary PublicKeyCredentialCreationOptions)
dictionary PublicKeyCredentialCreationOptions {required PublicKeyCredentialRpEntity rp ;required PublicKeyCredentialUserEntity user ;required BufferSource challenge ;required sequence <PublicKeyCredentialParameters >pubKeyCredParams ;unsigned long timeout ;sequence <PublicKeyCredentialDescriptor >excludeCredentials = [];AuthenticatorSelectionCriteria authenticatorSelection ;sequence <DOMString >hints = [];DOMString attestation = "none";sequence <DOMString >attestationFormats = [];AuthenticationExtensionsClientInputs extensions ; };
rp, of type PublicKeyCredentialRpEntity-
该成员包含了发出请求的 Relying Party 的名称与标识符。
其值的
name成员为必须项。更多细节见 § 5.4.1 Public Key Entity Description (dictionary PublicKeyCredentialEntity)。其值的
id成员指定凭证应当作用域(scoped)到的 RP ID。若省略,则其值将为CredentialsContainer对象的 relevant settings object 的 origin 的 effective domain。更多细节见 § 5.4.2 Relying Party Parameters for Credential Generation (dictionary PublicKeyCredentialRpEntity)。 user, of type PublicKeyCredentialUserEntity-
其值的
name、displayName与id成员为必需项。id在未来某些认证流程中可以作为userHandle被返回,并用于覆盖在同一 authenticator 上具有相同和rp.id的可发现凭证(discoverable credentials)。user.idname与displayName可以被 authenticator 和 client 在未来的认证流程中用于帮助用户选择凭证,但不会在未来的认证流程结果中返回给 Relying Party。更多细节见 § 5.4.1 Public Key Entity Description (dictionary PublicKeyCredentialEntity) 和 § 5.4.3 User Account Parameters for Credential Generation (dictionary PublicKeyCredentialUserEntity)。
challenge, of type BufferSource-
该成员指定一个 challenge,认证器在为新创建的凭证生成 attestation object 时会与其它数据一同对其进行签名。参见安全注意事项 § 13.4.3 Cryptographic Challenges。
pubKeyCredParams, of type sequence<PublicKeyCredentialParameters>-
该成员列出了 Relying Party 支持的密钥类型和签名算法,按从最优先到最不优先的顺序排列。允许重复,但会被有效忽略。client 与 authenticator 会尽最大努力创建最优先类型的凭证。如果无法创建任何列出的类型,则
create()操作将失败。希望支持广泛 authenticators 的 Relying Parties 应至少包含下列
COSEAlgorithmIdentifier值:-
-8 (Ed25519)
-
-7 (ES256)
-
-257 (RS256)
可根据需要加入更多签名算法。
-
timeout, of type unsigned long-
该可选成员指定以毫秒为单位的时间,表示 Relying Party 愿意等待调用完成的时间。此值作为提示,且可能被 client 覆盖。
excludeCredentials, of type sequence<PublicKeyCredentialDescriptor>, defaulting to[]-
Relying Party 应使用此可选成员列出映射到该 用户账号 的任何现有凭证(由
user.id标识)。这可确保新的凭证不会在已经包含映射到该用户账号的凭证的 authenticator 上创建。如果会出现这种情况,则请求客户端引导用户使用不同的 authenticator,如果失败则返回错误。 authenticatorSelection, of type AuthenticatorSelectionCriteria-
Relying Party 可使用此可选成员指定认证器必须或应满足的能力与设置,以参与
create()操作。见 § 5.4.4 Authenticator Selection Criteria (dictionary AuthenticatorSelectionCriteria)。 hints, of type sequence<DOMString>, defaulting to[]-
该可选成员包含零个或多个来自
PublicKeyCredentialHint的元素,用以指导用户代理与用户交互。请注意尽管元素来自枚举,但其类型为DOMString。见 § 2.1.1 Enumerations as DOMString types。 attestation, of type DOMString, defaulting to"none"-
Relying Party 可使用此可选成员指定关于 attestation conveyance 的偏好。其值应当是
AttestationConveyancePreference的成员。Client platforms 必须忽略未知值,并将未知值视为该成员不存在。默认值为
none。 attestationFormats, of type sequence<DOMString>, defaulting to[]-
Relying Party 可使用此可选成员指定对 attestation 语句格式的偏好,这些格式由 authenticator 使用。值应当取自 IANA “WebAuthn Attestation Statement Format Identifiers” 注册表(由 [IANA-WebAuthn-Registries] 建立),并按偏好顺序排列。允许重复但会被忽略。该参数为建议性,authenticator 可以使用未在该参数中列举的 attestation 语句。
默认值为空列表,表示不偏好任何格式。
extensions, of type AuthenticationExtensionsClientInputs-
Relying Party 可使用此可选成员提供 client extension inputs,请求 client 与 authenticator 进行额外处理。例如,Relying Party 可以请求客户端返回关于已创建 credential 的附加信息。
扩展框架在 § 9 WebAuthn Extensions 中定义。一些扩展在 § 10 Defined Extensions 中定义;请参阅由 [IANA-WebAuthn-Registries](由 [RFC8809] 建立)维护的注册表,以获取已注册 WebAuthn 扩展 的最新列表。
5.4.1.
公钥实体描述(字典 PublicKeyCredentialEntity)
PublicKeyCredentialEntity
字典描述一个 用户账户,或与之关联/限定(scope)的 WebAuthn
Relying Party,即公钥凭证的归属对象。
dictionary PublicKeyCredentialEntity {required DOMString name ; };
name,类型为 DOMString-
该实体的用户友好名称。其作用依赖
PublicKeyCredentialEntity的具体用法:-
[已弃用] 被
PublicKeyCredentialRpEntity继承时,表示 Relying Party 的用户友好标识,仅用于展示。例如:"ACME有限公司","欢乐部件公司" 或 "ОАО Примертех"。由于许多 客户端 并不显示该属性,该成员已弃用,但为兼容仍然必需。Relying Party 可将其值设置为 RP ID 作为默认。
-
Relying Party 在设置
name或展示值时,应该按照 [RFC8266] 第2.3节对昵称字符串的标准执行格式化和校验。 -
此字符串可包含语言及书写方向元数据。Relying Party 如设置为非RP ID值,建议一并给出相关元数据。元数据编码方式见 § 6.4.2 语言与方向编码。
-
客户端在将
name展示给用户,或作为 authenticatorMakeCredential 操作参数使用前,应如RFC8266和PRECIS所述进行标准化和安全性处理。
-
-
被
PublicKeyCredentialUserEntity继承时,则为该 用户账户 的用户友好标识。此标识是 客户端 展示给用户用以帮助其识别凭证归属的主显示值。常见如 "alexm", "+14255551234", "alex.mueller@example.com" 或 "alex.mueller@example.com (prod-env)"。
-
Relying Party 可允许用户自定义该值。并应依照 [RFC8265] 第3.4.3节对用户名的规范,对
name进行检验和处理。 -
该字符串可以包含语言和方向元数据。Relying Party 建议提供此类元信息。见 § 6.4.2 语言与方向编码。
-
客户端在展示或作为 authenticatorMakeCredential 参数前,应参照 [RFC8265] 和PRECIS用户名规范对值进行处理。
-
当 客户端、客户端平台 或 认证器 展示
name应使用 UI 元素清晰包裹,避免内容溢出到其它元素中。存储
name时允许进行截断,详见 § 6.4.1 字符串截断,建议阈值不少于64字节。 -
5.4.2.
凭证生成时的Relying Party参数(字典 PublicKeyCredentialRpEntity)
PublicKeyCredentialRpEntity
字典用于在创建新凭证时提供额外的 Relying
Party 属性。
dictionary PublicKeyCredentialRpEntity :PublicKeyCredentialEntity {DOMString id ; };
id,类型为 DOMString-
该 Relying Party 实体的唯一标识符,用作 RP ID。
5.4.3.
凭证生成时的用户账户参数(字典 PublicKeyCredentialUserEntity)
PublicKeyCredentialUserEntity
字典用于在新建凭证时提供额外的用户账户属性。
dictionary PublicKeyCredentialUserEntity :PublicKeyCredentialEntity {required BufferSource id ;required DOMString displayName ; };
id,类型为 BufferSource-
该用户账户的 user handle。 user handle 是一个最大长度不超过64字节的不透明字节序列(byte sequence),不应向用户展示。
为确保安全,认证和授权决策必须基于
id成员,而不可基于displayName或name。参见[RFC8266]第6.1节。user handle 禁止包含用户的个人身份信息(PII),如用户名、邮箱等;详见 § 14.6.1 User Handle 内容。user handle 不能为空。
即使是 不可发现凭证,不同用户的 user handle 也不应是常量,否则若认证器一律创建可发现凭证,多用户会互相影响。
displayName, 类型为 DOMString-
该用户账户的一个用户友好名称,仅用于显示。Relying Party 应让用户自主选择,且不应做过多限制。如果没有合适用户友好名称,则应设为空字符串。
例如: "Alex Müller", "Alex Müller (ACME Co.)", "田中倫" 等。
-
Relying Party 在设置非空字符串或展示非空字符串时,应按 [RFC8266] 第2.3节进行处理。
-
此字符串可包含语言和方向元数据。建议 Relying Party 提供此信息,见 § 6.4.2 语言与方向编码。
-
客户端 在展示非空displayName或作为 authenticatorMakeCredential 参数前,应做上述安全合规检测。
当 客户端、客户端平台 或 认证器 展示
displayName,应通过UI包裹,防止UI溢出。存储
displayName时可截断,建议最小64字节,详见 § 6.4.1 字符串截断。 -
5.4.4.
认证器选择条件(字典 AuthenticatorSelectionCriteria)
WebAuthn Relying
Parties 可以通过 AuthenticatorSelectionCriteria
字典来指定认证器属性需求。
dictionary AuthenticatorSelectionCriteria {DOMString authenticatorAttachment ;DOMString residentKey ;boolean requireResidentKey =false ;DOMString userVerification = "preferred"; };
authenticatorAttachment, 类型为 DOMString-
若存在,仅筛选与指定认证器连接模式匹配的认证器(详见 § 6.2.1)。如无则不限模式。值建议为
AuthenticatorAttachment的成员,但 客户端平台 必须忽略未知值。另见
authenticatorAttachment,用于确认成功注册/认证使用的连接模式。 residentKey, 类型为 DOMString-
指定 Relying Party 希望创建的 客户端可发现凭证 的程度。“resident” 为历史术语,值建议为
ResidentKeyRequirement内成员,平台必须忽略未知值。若缺省则根据requireResidentKey判断。详见该枚举描述。 requireResidentKey, 类型为 boolean, 默认false-
为兼容Level 1保留,建议仅当
residentKey为required时设为 true。 userVerification, 类型为 DOMString,默认"preferred"-
指定 Relying Party 对 用户验证 的需求。建议值为
UserVerificationRequirement,平台必须忽略未知值。详见
UserVerificationRequirement中各值定义。
5.4.5. 认证器连接模式枚举(enum AuthenticatorAttachment)
该枚举的值描述认证器的连接模式。Relying Party 在调用 navigator.credentials.create()
创建凭证时用于表达其对 认证器连接的偏好,客户端据此报告操作所用实际连接模式。
enum AuthenticatorAttachment {"platform" ,"cross-platform" };
注意: AuthenticatorAttachment
枚举故意未被直接引用,见 § 2.1.1 DOMString类型枚举。
注意: 认证器连接模式
选项仅在 [[Create]](origin, options, sameOriginWithAncestors)
操作支持。RP 可用以确保创建漫游凭证或本地凭证,便于跨设备使用或当前设备便捷认证。[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
操作无此选项,届时客户端和用户会选择最合适凭证,受 allowCredentials
限制。
5.4.6.
常驻密钥需求枚举(enum ResidentKeyRequirement)
enum ResidentKeyRequirement {"discouraged" ,"preferred" ,"required" };
注意: ResidentKeyRequirement
枚举故意未被直接引用,见 § 2.1.1 DOMString类型枚举。
该枚举描述 Relying Party 对 客户端可发现凭证(以前称为常驻凭证resident credential或resident key)的需求:
discouraged-
Relying Party 更倾向于创建 服务器端凭证,但亦接受 客户端可发现凭证。客户端与认证器应尽量创建服务器端凭证。
注意:Relying Party 无法要求必须创建为服务器端凭证,并且 Credential Properties Extension 可能不返回
rk字段,因此RP可能无法准确得知类型以及凭证复用行为。 preferred-
Relying Party 更倾向于创建 客户端可发现凭证,但亦接受服务器端凭证。客户端与认证器应尽量创建可发现凭证,必要时指导用户启用用户验证,其优先级高于
userVerification。 required-
Relying Party 要求必须创建 客户端可发现凭证。如若无法创建,客户端必须返回错误。
注意:Relying Party 可通过 Credential Properties Extension 的 resident key credential
property 判断是否创建了可发现凭证。这在 authenticatorSelection.residentKey
为 discouraged 或 preferred 时尤为重要,因为此时认证器可创建任意类型。
5.4.7.
声明传递 偏好枚举(enum AttestationConveyancePreference)
WebAuthn Relying
Parties 可以使用 AttestationConveyancePreference
指定在凭证生成时关于声明传递的偏好。
enum AttestationConveyancePreference {"none" ,"indirect" ,"direct" ,"enterprise" };
注意: AttestationConveyancePreference
枚举特意未被直接引用,详见 § 2.1.1 DOMString类型枚举。
none-
Relying Party 不关心认证器声明。例如,为了避免处理向 Relying Party 传递标识信息时获取用户同意,或减少与 Attestation CA 或 Anonymization CA 往返。当 认证器 生成的 声明语句 不是自声明时,客户端 会将其替换为 None 类型声明语句。
这是默认选项,未知值也将视为此行为。
indirect-
Relying Party 希望获得可验证的声明语句,但允许 客户端 决定如何获取该声明语句。客户端可用 Anonymization CA 生成的声明替换认证器声明以保护隐私,或帮RP验证。
注意:此方式不能保证 Relying Party 能一定获取到可验证声明。比如若认证器使用 自声明,客户端未做更改时即如此。
direct-
Relying Party 希望直接获得认证器生成的声明语句原文。
enterprise-
Relying Party 希望获得企业声明,即可能包含可唯一标识认证器信息的声明语句。适用于受控的企业场景以绑定注册到特定认证器。除非代理或认证器配置允许,不能提供企业声明给请求 RP ID。如允许,代理应在调用生成凭证时向认证器表明请求企业声明,并原封不动传递回 Relying Party。
5.5.
断言生成选项(字典 PublicKeyCredentialRequestOptions)
PublicKeyCredentialRequestOptions
字典向 get()
提供生成断言所需的数据。其 challenge
成员必须存在,其它成员均为可选。
dictionary PublicKeyCredentialRequestOptions {required BufferSource challenge ;unsigned long timeout ;DOMString rpId ;sequence <PublicKeyCredentialDescriptor >allowCredentials = [];DOMString userVerification = "preferred";sequence <DOMString >hints = [];AuthenticationExtensionsClientInputs extensions ; };
challenge,类型为 BufferSource-
该成员指定认证器生成认证断言时与其它数据一起签名的challenge。参见安全注意事项 § 13.4.3 加密挑战。
timeout,类型为 unsigned long-
该可选成员指定
get()调用允许等待的毫秒数。此值为提示,实际等候时间可能由客户端覆盖。 rpId,类型为 DOMString-
该可选成员指定 Relying Party 所声明的 RP ID。客户端 必须验证 Relying Party 的 origin 是否与此 RP ID 所作用域一致。认证器 必须确保该 RP ID 完全等于将被用于凭证的 rpId。 如未指定,该值为
CredentialsContainer对象的 相关设置对象的 origin 的 有效域名。 allowCredentials, 类型为 sequence<PublicKeyCredentialDescriptor>,默认为[]-
该可选成员用于 客户端 查找本次认证流程中可用的 认证器。主要有两种用法:
-
如待认证用户已明确(如用户输入了用户名),Relying Party 应用此列表枚举该用户下的所有凭证描述,供 client 优化体验。Relying Party 不必因用户验证与否而提前过滤;client 会自动忽略不满足要求的凭证。建议尽量填写
transports属性提升体验。详情见§ 14.6.3关于凭证ID的隐私泄露。 -
若认证用户尚未明确,Relying Party 可省略此成员,此时仅会利用可发现凭证,且最终
AuthenticatorAssertionResponse的userHandle可能揭示用户身份。如多可发现凭证,平台将列出供用户选择(见第7步)。
若非空数组,若均不可用客户端必须报错。列表按喜好降序排列。
-
userVerification, 类型为 DOMString,默认"preferred"-
该可选成员指定RP对
get()操作的用户验证需求。建议信息为相应枚举成员,平台须忽略未知值,只筛选能满足该需求的认证器。详见
UserVerificationRequirement描述。 hints,类型为 sequence<DOMString>,默认为[]-
可选成员,包含零或多个
PublicKeyCredentialHint元素指导代理与用户交互。注意其类型为 DOMString,详见 § 2.1.1 枚举字符串类型。 extensions,类型为 AuthenticationExtensionsClientInputs-
Relying Party 可使用该可选成员用于输入扩展请求客户端或认证器做特殊处理。扩展框架定义见 § 9 WebAuthn 扩展,扩展注册表见 [IANA-WebAuthn-Registries]。
5.6. 使用 AbortSignal 中止操作
建议开发者使用 AbortController
管理 [[Create]](origin, options, sameOriginWithAncestors)
与 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
操作。
详见 DOM § 3.3
AbortController 与 AbortSignal 用法。
注意: DOM § 3.3
AbortController与AbortSignal用法明确规定,当 AbortSignal
被中止时,平台API必须立即拒绝Promise。
鉴于 [[Create]](origin, options, sameOriginWithAncestors)
和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
逻辑结构复杂,两者分别在API主入口、认证会话前启动以及认证器会话期间三处检测该属性,确保遵从规范。
可见性和 焦点 状态影响 Window
关联文档的 [[Create]]
和 [[DiscoverFromExternalSource]]
操作是否继续。当与文档关联的 Window
失去焦点时,上述操作应中止。
5.7. WebAuthn 扩展输入与输出
下列小节定义了用于传递 WebAuthn 扩展输入与输出的数据类型。
注意: 认证器扩展输出作为认证器数据的一部分传递(见表 1)。
注意:下方定义的类型——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-
此成员包含由依赖方提供的 challenge 的 base64url 编码。参见 § 13.4.3 密码挑战安全考量。
origin, 类型为 DOMStringcrossOrigin, 类型为 boolean-
此可选成员包含传给 内部方法的
sameOriginWithAncestors参数的取反值。 topOrigin, 类型为 DOMString-
此可选成员包含请求方的完全限定顶级源,语法定义见[RFC6454]。仅在调用上下文与其祖先非同源(即same-origin with its ancestors为假时)设置,亦即
crossOrigin为true。 - [保留] tokenBinding
-
此可选成员包含与Token Binding协议 [TokenBinding]相关的信息。缺省表示客户端不支持 token binding
注意:虽然Token Binding 曾在 WebAuthn Level 1 和 Level 2 出现,其在 Level 3 不再使用。tokenBinding 字段被保留,不会被其他用途复用。
status, 类型为 DOMString-
此成员应为
TokenBindingStatus的成员,但客户端平台必须忽略未知值,将未知值视为tokenBinding 成员不存在。已知时,该成员为下列之一:注意: 枚举
TokenBindingStatus故意未被引用,详见§ 2.1.1 枚举作为 DOMString 类型。 id, 类型为 DOMString-
当
status为present时,该成员必须存在, 并且是向 依赖方通信时所用 Token Binding ID 的 base64url 编码。
注意: 获得 Token Binding ID 是客户端平台特定的操作。
CollectedClientData
结构用于客户端计算如下内容:
- 客户端数据的 JSON 兼容序列化
-
这是对
CollectedClientData字典执行 JSON 兼容序列化算法 的结果。 - 序列化客户端数据的哈希
-
这是客户端数据的 JSON 兼容序列化的哈希(用 SHA-256 计算),由客户端构造。
5.8.1.1. 序列化
CollectedClientData
的序列化是 JSON 值序列化为字节算法的子集。它产生 CollectedClientData
的一个有效 JSON 编码,但也为校验器提供了可利用的附加结构而无需集成完整 JSON 解析器。推荐校验器采用标准 JSON 解析,但如需精简可采用下方有限算法。该校验仅需要 base64url 编码、追加字节串(可写入模板)、简单条件判断(假定输入无需转义)。
序列化算法通过将连续的字节串附加到最初为空的部分结果,直到获得完整结果。
-
令 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),再加以四位小写十六进制表示该码点的数字。
-
附加 0x22(
")到 encoded。 -
函数返回 encoded 的值。
5.8.1.2. 有限校验算法
如无法支持完整 JSON 解析器,校验器可用如下算法校验编码后的CollectedClientData:
-
算法输入为:
-
字节串 clientDataJSON,即序列化的
clientDataJSON。 -
字符串 type,为期望的
type。 -
字节串 challenge,为
PublicKeyCredentialRequestOptions或PublicKeyCredentialCreationOptions中给定的 challenge 字节串。 -
字符串 origin,为发起请求的预期
origin。 -
可选字符串 topOrigin,为可用时发起请求的预期
topOrigin。 -
布尔值 requireTopOrigin,仅当需在 topOrigin 已定义但
topOrigin不在 clientDataJSON 时校验失败才为 true。 该算法与 Web Authentication Level 2 的JSON 兼容序列化算法向后兼容,前提requireTopOrigin为false。
-
-
定义 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()
中用于判定客户端是否以及如何能够访问该凭证。
凭证记录的凭证描述符是该凭证记录属性的一个子集,
并反映了 PublicKeyCredential
对象由 create()
和 get()
返回的部分字段。
type, 类型为 DOMString-
该成员包含调用者所指公钥凭证的类型。其值应为
PublicKeyCredentialType的成员,但客户端平台必须忽略类型未知的PublicKeyCredentialDescriptor。 但若所有元素都因类型未知被忽略,则必须报错,因为空的allowCredentials在语义上有特殊意义。此值应设置为代表被标识公钥凭证源的凭证记录中的 type 项。该字段对应
type字段, 同步于PublicKeyCredential。 id, 类型为 BufferSource-
该成员包含调用者所指公钥凭证的凭证 ID。
应设置为代表被标识公钥凭证源的凭证记录中的 id 项。这对应于
rawId字段, 是PublicKeyCredential的一部分。 transports, 类型为 sequence<DOMString>-
该可选成员包含客户端可能如何与被标识公钥凭证的管理认证器通信的提示。 其值应为
AuthenticatorTransport的成员, 但客户端平台必须忽略未知值。应设置为标识的公钥凭证源的凭证记录之 transports 项。它对应于
方法, 来源为用response.getTransports()PublicKeyCredential结构和create()操作创建的对象。
5.8.4. 认证器传输类型枚举(枚举 AuthenticatorTransport)
enum AuthenticatorTransport {"usb" ,"nfc" ,"ble" ,"smart-card" ,"hybrid" ,"internal" };
注意: AuthenticatorTransport
枚举被有意设计为不被直接引用,详见 § 2.1.1 枚举作为 DOMString 类型。
getTransports()
方法获知某公钥凭证支持的传输类型。
5.8.5. 密码算法标识符(类型定义 COSEAlgorithmIdentifier)
typedef long ;COSEAlgorithmIdentifier
COSEAlgorithmIdentifier
的值是用于标识密码算法的数字。
算法标识符应取自 IANA COSE 算法注册表 [IANA-COSE-ALGS-REG],如
"ES256" 用 -7,"RS256" 用 -257。
COSE 算法注册表留有由COSE 密钥中其它参数指定的选项空间。为促进互操作性,本规范对凭证公钥作如下额外要求:
-
算法为 ES256(-7)的密钥必须将 crv 参数指明为 P-256 (1),且不得使用压缩点格式。
-
算法为 ES384(-35)的密钥必须将 crv 参数指明为 P-384 (2),不得使用压缩点格式。
-
算法为 ES512(-36)的密钥必须将 crv 参数指明为 P-521 (3),不得使用压缩点格式。
-
算法为 EdDSA(-8)的密钥必须将 crv 参数指明为 Ed25519 (6)。(这类密钥在 COSE 中总是压缩的。)
这些约束与 [RFC9053] 第 2.1 节 的推荐做法一致。
注意:要正确实现这些算法的签名校验需做很多检查。其中之一是处理未压缩椭圆曲线点时,应校验该点真正在曲线上。此检查易被加密库和其他代码遗漏,需特别重视。
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 依赖方可能用于实现特定工作流和用户体验的有限客户端能力集。
依赖方可通过 getClientCapabilities()
方法获取 PublicKeyCredential
支持的能力。
注意: ClientCapability
枚举被有意设计为不被直接引用,详见 § 2.1.1 枚举作为 DOMString 类型。
conditionalCreate-
WebAuthn 客户端支持用于注册流程的
conditional调解。详见 § 5.1.3 新建凭证 - PublicKeyCredential 的 [[Create]](origin, options, sameOriginWithAncestors) 内部方法。
conditionalGet-
WebAuthn 客户端支持用于认证流程的
conditional调解。该能力等价于
isConditionalMediationAvailable()返回true。 hybridTransport-
WebAuthn 客户端支持
hybrid传输方式。 passkeyPlatformAuthenticator-
WebAuthn 客户端支持本地或通过
hybrid传输方式使用 passkey 平台认证器。 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-
表示信赖方认为用户将通过泛用型认证器(如智能手机)满足该请求。例如,某消费者信赖方 可能认为,只有极少数客户拥有专用的安全密钥。该选项同时意味着本地平台认证器 不应在界面中被提升展示。
为兼容老版用户代理,当本提示用于
PublicKeyCredentialCreationOptions时,authenticatorAttachment应被设置为cross-platform。
5.9. 权限策略集成
本规范定义了两个由特性标识符标识的由策略控制的特性
:
"publickey-credentials-create"
和
"publickey-credentials-get"。
它们的 默认允许列表 都为
'self'。[Permissions-Policy]
Document的
权限策略决定了该文档中的任何内容能否成功调用Web认证API,即,
通过
navigator.credentials.create({publicKey:..., ...})
或
navigator.credentials.get({publicKey:..., ...})
。如果在文档中被禁用,则该文档的内容均无法使用上述方法:尝试调用将会返回错误。
注意: [CREDENTIAL-MANAGEMENT-1]中定义的算法实际执行权限策略的评估。因为需要当可以访问当前设置对象时进行评估。[[Create]](origin, options, sameOriginWithAncestors)
和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
的内部方法无此访问能力,因为它们是被CredentialsContainer的创建凭据和请求凭据抽象操作并行调用的。[CREDENTIAL-MANAGEMENT-1]。
5.10. 在 iframe 元素内使用 Web Authentication
Web
认证 API 默认在跨域
iframe
中被禁用。
如需覆盖默认策略,并允许跨域
iframe
调用 Web认证API
的 [[Create]](origin, options, sameOriginWithAncestors)
和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
方法,
需要在
allow
属性中
添加
publickey-credentials-create
或
publickey-credentials-get
特性标识符,
并写入
allow
属性值中。
信赖方在嵌入式场景下使用 WebAuthn API 时,建议复习 § 13.4.2 嵌入式可见性注意事项,了解UI 伪装及其可能的缓解措施。
5.11. 跨关联来源使用 Web Authentication
默认情况下,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 提供。文档返回要求如下:
-
内容类型必须为
application/json。 -
顶层 JSON 对象必须包含名为
origins的 key,其值为包含一个或多个 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客户端 至少需支持5个可注册来源标签。客户端策略应定义上限以防止滥用。
WebAuthn客户端访问该well-known端点时,必须不带凭据、不带referrer,且使用https: 协议。若出现重定向,所有重定向也必须显式为https:协议。
支持该功能的WebAuthn客户端
应在 getClientCapabilities() 响应内包含 relatedOrigins。
5.11.1. 关联来源验证
关联来源验证过程 ,给定参数 callerOrigin 与 rpIdRequested,流程如下:
-
设 maxLabels 为客户端策略允许的最大可注册来源标签个数。
-
拉取 rpIdRequested 的
webauthnwell-known URL [RFC8615] (即https://rpIdRequested/.well-known/webauthn),不带凭据、不带referrer且使用https:协议。-
若拉取失败、响应内容类型非
application/json,或(跟随重定向后)响应码非200,则抛出 "SecurityError"DOMException。 -
若资源主体不是有效JSON对象,则抛出 "
SecurityError"DOMException。 -
若JSON对象的 origins 属性缺失或者不是字符串数组,则抛出 "
SecurityError"DOMException。
-
-
令 labelsSeen 初始化为空集合。
-
对每个 originItem 属于 origins:
-
返回
false。
6. WebAuthn 认证器模型
Web认证API 隐含了一套针对WebAuthn认证器 的抽象功能模型。 本节描述该认证器模型。
客户端平台可按需实现和暴露本抽象模型。不过,当平台支持的认证器上运行的 Web 认证 API 实现时, 客户端的行为必须与§ 5 Web认证API中定义的行为无法区分。
注意: [FIDO-CTAP] 是该模型的一个具体实例,但它返回的数据与 WebAuthn API 算法所期望的存在差异。CTAP2 响应消息使用整数键构造 CBOR 映射,而本规范定义的相同对象使用字符串键。客户端需要对数据进行必要的转换。[FIDO-CTAP] 规范在 §6. 认证器API中详细阐述了 CTAP2 整数键与 WebAuthn 字符串键之间的映射。
对认证器来说,本模型定义它们必须支持的逻辑操作和向客户端与WebAuthn信赖方暴露的数据格式。然而,除非为与信赖方互操作所必需,否则该模型不定义认证器与客户端设备通信的细节。例如,不定义经 USB 或 NFC 之类传输连接认证器的协议。 同样,也不定义特定的错误码及其返回方式;不过, 会按客户端所需以错误行为的形式给出。因此,文中提及具体错误码旨在说明 哪些错误条件必须能互相区分(或不能),从而保证客户端实现的合规与安全。
信赖方可以在创建凭据时和/或生成断言时,通过指定各类认证器特性,影响认证器的选择,这些特性通过凭据创建选项或断言生成选项传递。底层算法将这些选项整理后传递给下文定义的相关认证器操作。
在该抽象模型中,认证器负责密钥管理与加密签名。它可以嵌入在 WebAuthn 客户端内部,也可单独置于其他设备内。认证器本身可以包含一个加密模块,其安全级别高于认证器的其他部分。对于集成在 WebAuthn 客户端中的认证器,这一点尤为重要,因为在这种情况下,该加密模块(例如 TPM)可被视为比认证器其余部分更可信。
每个认证器存储一个 凭据映射(credentials map),即从 (rpId, userHandle) 到 公钥凭据源 的有序映射。
此外,每个认证器有一个认证器验证全局唯一标识(AAGUID,AAGUID), 这是一个128位标识符,表示认证器类型(例如品牌和型号)。AAGUID 必须由制造商选择,对所有基本一致的设备一致,且与其他认证器类型的 AAGUID 有很高概率不同。AAGUID 应该随机生成以确保唯一性。信赖方可以借助AAGUID,通过其他信息源,推断认证器的认证级别和密钥防护强度。信赖方也可尝试据此识别认证器制造商——不过如未要求并验证证明(attestation),AAGUID 并非可证明真实身份。
认证器的核心功能是提供WebAuthn签名,签名内容绑定了多种上下文数据。这些数据会在签名请求自服务器发出到设备的过程中被观察并附加。对于服务器来说,验证签名时需检验这些绑定是否符合预期。这些上下文绑定分为两类:由 信赖方或客户端添加的称为 客户端数据;由认证器添加的为 认证器数据。认证器只对客户端数据进行哈希并加以签名,不关心内容本身。为节省带宽及处理量,客户端将 客户端数据 哈希后,将哈希值传送给认证器,由认证器对该哈希加上本身认证器数据的组合进行签名。
该设计目标总结如下:
-
签名生成机制要适应认证器与客户端设备链接带宽/延迟极低的情形。包括 BLE、NFC 等场景。
-
认证器处理的数据应简明、便于底层代码理解,尤其不应要求认证器解析如 JSON 这种高层编码。
-
客户端与认证器均应能灵活增添上下文绑定信息。
-
尽可能重用已有编码格式以便采纳与实现。
认证器生成加密签名用于两种不同目的:
-
证明签名(attestation signature):当通过authenticatorMakeCredential操作创建新的公钥凭据时生成。证明签名为认证器及凭据的某些特性提供加密佐证。例如签名会声明认证器类型(AAGUID)以及凭据公钥。签名由证明私钥完成,其选择依据所需的证明类型。详细可见§ 6.5证明。
-
断言签名(assertion signature):调用 authenticatorGetAssertion 方法时生成。用于认证器声明用户已就某事务给出同意,如登录、付款等。因此,断言签名声明,某一 认证器 持有特定 凭据私钥,并已最合理地判断交易发起人确为签名创建人;还会声明客户端数据(如同意方式、提示内容)供调用者参考。断言签名格式见下方图 4。
术语 WebAuthn签名 同时指 证明签名与 断言签名。这些签名的格式和生成过程在下文中详细说明。
6.1. 认证器数据(Authenticator Data)
认证器数据结构用于编码由认证器进行的上下文绑定。这些绑定由认证器自行控制,其信任等级依赖于WebAuthn信赖方对认证器安全属性的评估。在某些极端情况下,认证器可能嵌入在客户端,其绑定与客户端数据相比可信度不高;而在另一极端,认证器可能为通过安全通道与客户端相连的高安全性硬件/软件独立实体。无论哪种情况,信赖方获得的认证器数据格式是相同的,并会依据对认证器的了解做出信任决策。
认证器数据采用紧凑但可扩展的编码格式。这是因为认证器可能是功能有限、功耗极低且软件堆栈远比客户端平台简单的设备。
认证器数据结构是一个不少于37字节的字节数组,布局如表 所示。
| 名称 | 长度(字节数) | 描述 |
|---|---|---|
| rpIdHash | 32 | RP ID的SHA-256哈希,凭据所作用域即此RP ID。 |
| flags(标志位) | 1 | 标志位(比特0为最低有效位): |
| signCount | 4 | 签名计数器,32位无符号大端整数。 |
| attestedCredentialData | 可变(若存在) | 证明凭据数据(如存在)。详见§ 6.5.1 证明凭据数据。长度依赖于credential ID长度及被证明的credential ID、 credential public key的长度。 |
| extensions | 可变(如存在) | 扩展定义的认证器数据。这是一个以扩展标识符为键、以认证器扩展输出为值的CBOR映射,详见§ 9 WebAuthn扩展。 |
RP ID在凭据创建以及生成断言时最初由客户端接收。然而它与其他客户端数据有重要区别:首先,其值不像客户端数据那样会在不同操作之间变化,而是在凭据生命期内保持不变;其次,在authenticatorGetAssertion期间,认证器会校验所请求凭据的RP ID与客户端传入一致。
-
当且仅当认证器进行了用户在场检测(test of user presence)时,才设置UP 标志;仅当认证器进行了用户验证时,设置UV 标志。
RFU位必须为0。 -
仅当凭据为多设备凭据时,才设置BE 标志。此值在注册流程后不得变动,详见§ 6.1.3 凭据备份状态。
-
如凭据备份状态不确定,或认证器怀疑凭据存在问题,不应设置BS标志。
-
如为证明签名,认证器必须设置AT标志并包含
attestedCredentialData。如为断言签名,则不得设置AT标志且不得包含attestedCredentialData。
判断证明凭据数据的长度,需要先根据前面的credentialId的长度确定credentialPublicKey的起始位置,再判断credentialPublicKey长度;参见RFC9052第7节。
6.1.1. 签名计数器(Signature Counter)注意事项
认证器应实现签名计数器功能。签名计数器可按凭据单独存储,也可全局存储于认证器主体。凭据初始签名计数器的值,由signCount字段指明,来源于认证器数据,由authenticatorMakeCredential产生。每次authenticatorGetAssertion操作成功,签名计数器按正数递增,并在随后的认证器数据中返回给WebAuthn信赖方。签名计数器用于协助信赖方检测认证器克隆,尤其对保护措施有限的认证器意义更大。
信赖方保存最近一次authenticatorGetAssertion操作返回的签名计数器,如尚未通过authenticatorGetAssertion,则保存authenticatorMakeCredential时的计数器。在随后的authenticatorGetAssertion操作中,信赖方比对本地保存的与新获得的signCount,如两者皆非零且新值小于等于旧值,则可能存在认证器克隆、功能异常,或出现服务端处理乱序。
签名计数器不增并不能直接判断当前操作来自克隆认证器还是原认证器。信赖方应依据各自容忍度或运营特性,权衡如何处理此类异常。
认证器:
6.1.2. FIDO U2F 签名格式兼容性
断言签名(即对认证器数据结构与序列化客户端数据哈希的拼接签名)格式兼容FIDO U2F认证签名格式(参见第5.4节)。
这是因为FIDO U2F认证响应消息中已签名数据的前37字节恰为合法的认证器数据,剩余32字节为序列化客户端数据哈希。该结构中rpIdHash即FIDO
U2F的application
parameter,除UP外其他flags始终为0,attestedCredentialData及extensions始终不存在。因此,可用本协议的断言签名验证FIDO
U2F认证签名。
6.1.3. 凭据备份状态
凭据备份资格与当前备份状态由BE和BS标志字段表示(详见上表)。
BE 标志在authenticatorMakeCredential操作时设定,并且不得更改。
BS 标志可以根据公钥凭据源当前状态变化。下表定义了有效组合及其含义。
建议信赖方将这些标志的最近值与用户账号一起保存,便于后续判断。
-
需要更多认证器:
当BE标志为
0时,凭据为单设备凭据且生成认证器不会允许该凭据被备份。单设备凭据无法防止单台设备丢失的风险。信赖方应保证每个用户账号有更多的认证器注册或有账号恢复机制。比如可提示用户再设置一个认证器,如漫游认证器或具备多设备凭据能力的认证器。
-
将用户升级为无密码账号:
当BS 标志由
0变1时,认证器表示凭据已备份,可抵御单台设备丢失。信赖方可提示用户升级账号安全、移除密码。
-
状态变化后增加认证方式:
当BS 标志由
1变0时,认证器表示凭据不再被备份,不再受单台设备丢失保护。用户可能主动关闭了备份服务,或因备份服务错误导致。此类变更后,信赖方应引导用户验证其他认证因子。若无其他凭据,应引导用户添加额外凭据,以避免失去账号访问。例如可提示再设置一个认证器,如漫游认证器或具多设备凭据的认证器。
6.2. 认证器分类
许多用例依赖于所用认证器的能力。 本节定义了这些能力的部分术语、主要组合及其能支持哪些用例。
例如:
-
笔记本电脑或许支持通过USB和蓝牙连接漫游认证器,而手机可能仅支持NFC。
上述示例阐释了认证器类型的主要特征:
这些特征彼此独立,可以任意组合,下表则列举命名了部分有代表性的认证器类型。
| 认证器类型 | 认证器连接形态 | 凭据存储形式 | 认证因子能力 |
|---|---|---|---|
| 二次因子平台认证器 | 平台 | 任意 | 单因子认证 |
| 用户验证平台认证器 | 平台 | 任意 | 多因子认证 |
| 二次因子漫游认证器 | 跨平台 | 服务端存储 | 单因子认证 |
| 密钥漫游认证器 | 跨平台 | 客户端存储 | 多因子认证 |
| 密钥平台认证器 | 平台 (transport
= internal)
或 跨平台 (transport
= hybrid)
| 客户端存储 | 多因子认证 |
二次因子平台认证器适合同一客户端设备的再次认证, 并可为新会话启动和恢复既有会话时增加安全层。 二次因子漫游认证器更常用于在某个客户端设备首次认证, 或在多用户共享的客户端设备上认证。
密钥平台认证器与密钥漫游认证器支持无密码多因子认证。 除证明持有凭据私钥外, 这些认证器还作为第二个认证因子支持用户验证,例如PIN或生物识别。 因而,认证器可同时充当两类认证因子, 实现多因子认证同时免除与信赖方共享密码的需要。 此类认证器还支持可发现凭据(又称密钥), 即可允许认证流程无需输入用户名。
用户验证平台认证器类别基本已被密钥平台认证器所取代,
但isUserVerifyingPlatformAuthenticatorAvailable方法仍在使用此定义。
上表未命名的其他组合用例价值较低:
-
具备可发现凭据但不支持多因子的漫游认证器, 可用于无用户名的单因子认证, 即仅凭用户标识和持有凭据私钥,对用户进行认证。 某些场景下这很有用,但用户一旦认证器被盗风险极高。
-
具备多因子但不支持可发现凭据的漫游认证器,可用于多因子认证,但要求用户身份已知,这样可能会泄露个人身份信息,详见§ 14.6.3 凭据ID隐私泄漏。
下节将更详细定义认证器连接形态、凭据存储形式及认证因子能力。
6.2.1. 认证器连接形态
客户端可通过多种机制与认证器通信。例如,客户端可以调用客户端设备专有API与物理绑定于本机的认证器通信。也可以通过标准化的跨平台传输协议(如蓝牙,见§ 5.8.4认证器传输枚举)发现并与跨平台连接的认证器通信。本地集成于客户端设备的认证器称为平台认证器,而由跨平台协议可达的则为漫游认证器。
-
平台认证器通过客户端设备专有传输方式,即平台连接,连接,通常不可从该客户端设备移除。绑定于平台认证器的公钥凭据称为平台凭据。
-
漫游认证器通过跨平台传输方式连接,即跨平台连接。此类认证器可从设备移除并在不同客户端设备间“漫游”。绑定于漫游认证器的公钥凭据称为漫游凭据。
某些平台认证器也可能在某些场景下充当漫游认证器。例如,内置于移动设备的平台认证器可通过蓝牙作为漫游认证器使用。 本机运行的客户端会将其视作平台认证器, 而其他设备上通过蓝牙通信的客户端则会认为它是漫游认证器。
平台认证器的主要用途是将特定客户端设备注册为“受信设备”, 这样客户端设备自身可在未来的认证中作为拥有要素。 用户因此可获得无需携带漫游认证器即可完成后续认证流程的便利,比如无需再掏钥匙或手机。
漫游认证器的用例包括:首次在新客户端设备上认证、临时设备或多人共用的客户端设备、无内置平台认证器的客户端设备, 或因政策/偏好要求认证器与所用设备分离时。 也可用作备份凭据以防其他认证器遗失。
6.2.2. 凭据存储形式
-
嵌入于认证器、客户端或客户端设备的持久性存储,例如安全元件。 这是客户端可发现公钥凭据源的技术要求。
-
将公钥凭据源加密(即加壳),仅本认证器才能解密(解壳),所得密文即为凭据ID。凭据ID由信赖方保存,并通过
allowCredentials参数传回认证器,使其解密并使用对应的公钥凭据源。这样可让认证器拥有无限制凭据存储空间,因为加密后的凭据源由信赖方保存而非认证器本身——但这种凭据使用前需先向信赖方取回。
认证器支持的存储策略决定其凭据存储形式:
请注意,支持可发现凭据的认证器可同时支持两种存储策略。此时,可针对不同凭据选择不同存储方式,但需受residentKey与requireResidentKey参数约束。
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,含有用户标识(user handle),由信赖方给定。 - requireResidentKey
-
由客户端确定的凭据创建流程的resient key有效需求布尔值。
- requireUserPresence
-
恒定布尔值
true,或当options.为mediationconditional且用户代理已采集用户同意时为FALSE。 - requireUserVerification
-
由客户端确定的凭据创建流程的用户验证有效需求布尔值。
- credTypesAndPubKeyAlgs
-
信赖方请求的一组
PublicKeyCredentialType与公钥算法(COSEAlgorithmIdentifier)对,按优先级从高到低排序。认证器尽力创建能支持的优先度最高的凭据。 - excludeCredentialDescriptorList
-
选填项,一组
PublicKeyCredentialDescriptor对象,由信赖方给定,意在告知认证器如知晓其中任何对象则不应再创建新凭据。 excludeCredentialDescriptorList中即为已知凭据。 - enterpriseAttestationPossible
-
布尔值,指示认证器可以返回唯一标识的attestation。
- attestationFormats
-
一串字符串,表示信赖方对attestation声明格式的偏好,按优先级从高到低排列。如认证器返回attestation,会尽量使用首选格式。
- extensions
当调用本操作时,认证器必须按如下流程操作:
-
检查所有输入参数语法是否正确且长度合规,否则返回"
UnknownError"错误并终止。 -
检查credTypesAndPubKeyAlgs中的至少一组
PublicKeyCredentialType与加密参数为认证器所支持,否则返回"NotSupportedError"错误并终止。 -
遍历excludeCredentialDescriptorList:
-
如在本认证器上查找
descriptor.返回非null,并且结果项的RP ID及type分别等于idrpEntity.和idexcludeCredentialDescriptorList., 则采集授权手势确认用户同意创建新凭据。授权手势必须含用户在场检测。若用户type- 同意新建凭据
-
返回"
InvalidStateError"错误并终止。 - 不同意
-
返回"
NotAllowedError"错误并终止。
注意:此授权手势只用于隐私目的,授权披露
descriptor.已被本认证器绑定,不是用于继续创建凭据。 若用户同意,客户端和信赖方即可知晓,引导用户用其它认证器。如用户不同意, 认证器则不会暴露该id已绑定,仅表现为用户拒绝新建凭据。id
-
-
如requireResidentKey为
true且认证器无法存储客户端可发现凭据源, 返回"ConstraintError"错误并终止。 -
如requireUserVerification为
true且认证器不能执行用户验证,返回"ConstraintError"错误并终止。 -
采集授权手势
,确认用户同意创建新凭据。
如认证器支持输出界面,则由其展示授权提示,否则由用户代理负责。应尽量展示
rpEntity.、idrpEntity.、nameuserEntity.和nameuserEntity.。displayName如requireUserVerification为
true,授权手势必须含用户验证。如requireUserPresence为
true,授权手势必须含用户在场检测。若用户未同意或用户验证失败则返回"
NotAllowedError"错误并终止。 -
授权手势完成且用户同意后,生成新凭据对象:
-
生成一对publicKey、privateKey密钥,采用认证器支持的
PublicKeyCredentialType及加密参数。 -
userHandle取自
userEntity.。id -
新建credentialSource 公钥凭据源,字段包括:
- type
- privateKey
-
privateKey
- rpId
-
rpEntity.id - userHandle
-
userHandle
- otherUI
-
认证器选择包含的任意信息。
-
如requireResidentKey为
true或认证器主动创建客户端可发现凭据源: -
否则:
-
将credentialSource序列化加密,仅本认证器可解密,所得即credentialId。
-
-
-
如创建凭据目标对象时出错,则返回"
UnknownError"错误并终止。 -
processedExtensions为认证器扩展处理结果,遍历所有受支持扩展。
-
判断认证器:
-
attestedCredentialData为包含credentialId与publicKey的证明凭据数据字节数组。
-
选择第一个被支持的attestation声明格式标识作为attestationFormat,若候选中无支持项则选择认证器最偏好的格式。
-
按§ 6.1 认证器数据生成authenticatorData字节数组,如有则包含attestedCredentialData与processedExtensions。
-
用§ 6.5.4 证明对象生成流程,以attestationFormat、authenticatorData、hash及enterpriseAttestationPossible生成新凭据的证明对象,详情见§ 6.5证明。
操作成功时,认证器向客户端返回证明对象。
6.3.3. authenticatorGetAssertion 操作
在调用此操作之前,客户端必须调用 authenticatorCancel 操作,以中止身份验证器会话中正在进行的所有其他操作。
此操作接收以下输入参数:
- rpId
- hash
-
由客户端提供的序列化客户端数据的哈希值。
- allowCredentialDescriptorList
-
一个可选的 列表,包含
PublicKeyCredentialDescriptor描述可被 Relying Party(可能已被客户端过滤)接受的凭据。 - requireUserPresence
-
常量布尔值
true。 将其作为伪参数包含在此,以简化将此抽象身份验证器模型应用于可能希望将用户在场测试设为可选项的实现,尽管 WebAuthn 本身不允许其为可选。 - requireUserVerification
-
用于断言的有效用户验证需求,一个由客户端提供的布尔值。
- extensions
-
一个由扩展标识符到其身份验证器扩展输入的 CBOR 映射,由客户端根据Relying Party所要求的扩展创建。
当调用此方法时,身份验证器必须执行以下步骤:
-
检查所有提供的参数是否语法正确且长度合适。如果不是,返回等价于"
UnknownError"的错误码并终止操作。 -
如果传入了 allowCredentialDescriptorList,则针对每个 descriptor 遍历 allowCredentialDescriptorList:
-
否则(未传入 allowCredentialDescriptorList),遍历此身份验证器的凭据映射,添加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,如果客户端传入的凭据列表(即 allowCredentialDescriptorList)长度大于等于2或未传入该列表。
注意:如果 allowCredentialDescriptorList 仅包含一个凭据并已成功使用,则其凭据ID不会返回,因为客户端已经知晓。此举可节省可能受限连接下的数据传输量,且该场景可能较常见。
-
authenticatorData
-
signature
-
selectedCredential.userHandle
注意:如果客户端传入了 allowCredentialDescriptorList,则返回的 userHandle 可能为
null,详见 userHandleResult。
-
如果身份验证器无法找到与指定Relying Party匹配并满足指定条件的凭据,则终止操作并返回错误。
6.3.4. authenticatorCancel 操作
此操作不接收输入参数,也不返回结果。
当客户端在身份验证器会话中调用此操作时,将终止该会话下正在进行的任何authenticatorMakeCredential 或 authenticatorGetAssertion 操作。身份验证器将停止提示或接受任何与已取消操作相关的用户输入。客户端会忽略身份验证器对已取消操作的任何后续响应。
如果此操作在一个未包含authenticatorMakeCredential 或 authenticatorGetAssertion 操作的身份验证器会话中被调用,则会被忽略。
6.3.5. silentCredentialDiscovery 操作
这是一项可选操作,身份验证器可以支持该操作以启用 conditional
用户介入。
其接收以下输入参数:
当调用此操作时,身份验证器必须执行以下步骤:
-
令 collectedDiscoverableCredentialMetadata 为新的列表,其项为 DiscoverableCredentialMetadata 结构体,包含以下字段:
-
返回 collectedDiscoverableCredentialMetadata。
6.4. 字符串处理
身份验证器可能需要存储由Relying
Party选择的任意字符串,例如 name
和 displayName
,它们包含在 PublicKeyCredentialUserEntity
中。本节讨论处理这些可能呈现给人类的任意字符串时需要实际注意的一些后果。
6.4.1. 字符串截断
API 中的每个任意字符串都需考虑身份验证器可能有限的资源。如果采用字符串截断作为处理方式,必须注意不要破坏字符串的值。
例如,仅基于 Unicode 码点的截断可能会导致字形簇(grapheme cluster)被截断。这可能会使该字形簇渲染出不同的字形,从而改变字符串含义,而非只移除整个字形。例如,图 展示了一个 UTF-8 编码字符串结尾,编码长度为 65 字节。如果要截断到 64 字节,则最后的 0x88 字节首先被移除以满足大小限制。由于这将导致一个不完整的 UTF-8 码点,剩余的该码点部分也必须一并移除。若还形成了不完整的字形簇,也应将该簇的剩余部分一并移除。
处理这些问题的主要责任在于客户端,以避免给身份验证器带来理解字符编码或 Unicode 字符属性的负担。下述子章节明确规定了客户端和身份验证器分别如何进行字符串截断的要求。
6.4.1.1. 客户端的字符串截断
当WebAuthn 客户端截断字符串时,Relying Party可观察到的截断行为必须满足以下要求:
选择的大小限制不得小于规定的最小支持长度。字符串可以被截断,使其在 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 中的字符串可能要写入定制的身份验证器,然后再读出来显示在其它平台。因此,语言和方向元数据被编码进字符串本身,以确保信息整体传递。
对于允许编码语言和方向元数据的字符串,方法是,在其码点末尾添加两段码点序列:
第一段:用码点 U+E0001 加上语言标签各字母的 ASCII 值,各值均加 U+E0000。例如,语言标签 “en-US” 被编码为 U+E0001, U+E0065, U+E006E, U+E002D, U+E0055, U+E0053。
第二段:只包含一个码点,可为 U+200E(“左至右标记”)、U+200F(“右至左标记”)或 U+E007F(“取消标签”)。前两者用于指示书写方向,但只有在无法自动正确判断方向时才建议用(例如一个包含 LTR 强字符开头的 RTL 字符串)。U+E007F 用于表明语言标签结束、与方向无关。
因此,字符串“حبیب الرحمان”可以有两种不同的 DOMString 值,具体取决于是否编码语言(本例因方向明确,无需方向性标记)。
-
原始字符串:U+062D, U+0628, U+06CC, U+0628, U+0020, U+0627, U+0644, U+0631, U+062D, U+0645, U+0627, U+0646
-
编码了“ar-SA”语言:U+062D, U+0628, U+06CC, U+0628, U+0020, U+0627, U+0644, U+0631, U+062D, U+0645, U+0627, U+0646, U+E0001, U+E0061, U+E0072, U+E002D, U+E0053, U+E0041, U+E007F
对可能已编码语言和方向的字符串进行处理时需注意,截断操作可能将语言标签截断为不同但依然有效的语言。最后的方向性标记或“取消标签”码点,可用来无歧义地标识截断。
6.5. 证明(Attestation)
认证器也应尽可能提供某种形式的证明。 如果认证器做到了,基本要求是认证器能够针对每个凭证公钥生成由WebAuthn 依赖方可验证的证明语句。通常,这个证明语句包含由证明私钥对已证明的凭证公钥和挑战生成的签名,以及由证明公钥提供来源信息的证书或类似数据,使依赖方可以做出信任决策。然而,如果没有可用的证明密钥对,则认证器可以使用相应的凭证私钥对凭证公钥执行自我证明, 或使用无证明。所有这些信息在每次生成新的公钥凭证时都会由认证器返回,整体以证明对象的形式给出。证明对象与包含被证明凭证数据的认证器数据以及证明语句之间的关系在下文图 中说明。
如果认证器采用自我证明或无证明,则不会为依赖方提供进行信任决策所需的来源信息。 在这些情况下,认证器不会向依赖方提供关于自身操作的任何保证。
证明对象(attestation object)的重要组成部分是 证明语句。这是一种签名数据对象,包含关于公钥凭据本身及创建它的身份验证器的信息。它包含一个由证明方密钥生成的证明签名(除了自我证明情形外,此时使用凭据私钥)。Relying Party要正确解释证明语句,需搞清楚证明的这两个方面:
-
证明语句格式是签名表示方式及各种上下文绑定如何被身份验证器并入证明语句中的方式。即,定义了证明语句的语法。各类平台(如 TPM、Android OS)已有多种证明语句格式,本规范通过 6.5.2 节 详述了可扩展支持多种格式的方法。格式本身用字符串标识,详见 8.1。
-
证明类型定义了证明语句的语义及其信任模型。具体来说,它规定了Relying Party在验证证明语句的加密有效性后,如何建立信任。此规范支持多种证明类型,详见 § 6.5.3 证明类型。
一般来说,证明语句格式和证明类型之间没有简单映射。例如,packed 格式既可用于所有 证明类型,而其它格式和类型则适用范围有限。
证明的隐私性、安全性和操作特点由下列因素决定:
证明类型和证明语句格式由身份验证器选择;Relying Party只能通过设置 attestation
以及 attestationFormats
参数表达偏好。
大多数身份验证器预计只支持少数几种证明类型及证明语句格式,而Relying Party会通过策略决定哪些类型可接受。Relying Party还需了解信任身份验证器的特性,可参考 FIDO Metadata Service [FIDOMetadataService]获取这类信息。
6.5.1. 证明的凭据数据
证明的凭据数据是在为凭据生成证明对象时,添加到认证器数据中的变长字节数组。其格式如表格 所示。
| 名称 | 长度(字节) | 说明 |
|---|---|---|
| aaguid | 16 | 认证器的AAGUID。 |
| credentialIdLength | 2 | credentialId 的字节长度 L,16 位无符号大端整数。值必须 ≤ 1023。 |
| credentialId | L | 凭据 ID |
| credentialPublicKey | 可变 | 以 COSE_Key 格式编码的 凭据公钥,如 [RFC9052] 第
7 节 所定义,使用 CTAP2 标准 CBOR 编码形式。
COSE_Key 编码的 凭据公钥 必须包含 "alg" 参数,并且不得包含其它可选参数。"alg" 参数必须是
COSEAlgorithmIdentifier。
编码后的 凭据公钥 还必须包含该密钥类型规范规定的所有其他必需参数,即对 "kty" 和 "alg"
必须要求的(见 [RFC9053] 第 2 节)。
|
6.5.1.1. credentialPublicKey COSE_Key
格式编码值示例
本节给出 ES256、PS256 和 RS256 签名算法下,COSE_Key 编码的椭圆曲线和 RSA 公钥示例。这些示例符合上面对 credentialPublicKey 值的规则,并以 CDDL [RFC8610] 展示以方便阅读。
[RFC9052] 第 7 节 定义了所有 COSE_Key 编码密钥的一般框架。特定算法下的密钥类型定义见 [RFC9053] 及下文涉及的其它规范。
下例为 EC2 格式(见 [RFC9053] 第 7.1 节)的 COSE_Key 编码椭圆曲线公钥,P-256 曲线、用于 ES256 签名算法(ECDSA w/ SHA-256,见 [RFC9053] 第 2.1 节):
{ 1 : 2 , ; kty: EC2 密钥类型 3 : -7 , ; alg: ES256 签名算法 -1 : 1 , ; crv: P-256 曲线 -2 : x , ; x 坐标,32 字节长度字节串 ; 例如,十六进制: 65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d -3 : y ; y 坐标,32 字节长度字节串 ; 例如,十六进制: 1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c }
下例为上面椭圆曲线公钥的 CTAP2 标准 CBOR 编码形式,其中换行和空白用于易读和与上面 CDDL 展示一致:
A5 01 02 03 26 20 01 21 58 20 65eda5a12577c2bae829437fe338701a10aaa375e1bb5b5de108de439c08551d 22 58 20 1e52ed75701163f7f9e40ddf9f341b3dc9ba860af7e0ca7ca7e9eecd0084d19c
下例是 COSE_Key 编码的 2048 位 RSA 公钥(见 [RFC8230] 第 4 节),用于 PS256 签名算法 (RSASSA-PSS with SHA-256,见 [RFC8230] 第 2 节):
{ 1 : 3 , ; kty: RSA 密钥类型 3 : -37 , ; alg: PS256 -1 : n , ; n: RSA 模数,256 字节长度字节串 ; 例如,十六进制(中间内容省略):DB5F651550...6DC6548ACC3 -2 : e ; e: 公钥指数,3 字节长度字节串 ; 例如,十六进制: 010001 }
下例为与上述相同公钥,但用于 RS256 签名算法(RSASSA-PKCS1-v1_5 with SHA-256):
{ 1 : 3 , ; kty: RSA 密钥类型 3 : -257 , ; alg: RS256 -1 : n , ; n: RSA 模数,256 字节长度字节串 ; 例如,十六进制(中间内容省略):DB5F651550...6DC6548ACC3 -2 : e ; e: 公钥指数,3 字节长度字节串 ; 例如,十六进制: 010001 }
6.5.2. 证明语句格式
如上所述,证明语句格式是指用于表示认证器对一组上下文绑定内容进行加密签名的数据格式。每种证明语句格式都必须按照如下模板进行定义:
-
支持的证明类型:
-
语法:该格式下证明语句的语法,使用 CDDL [RFC8610] 描述,在
$$attStmtType扩展点(§ 6.5.4 生成证明对象)中定义。 -
签名过程: 该 签名过程 用于根据要被证明的公钥凭据、包含 用于证明的认证器数据 的认证器数据结构以及序列化客户端数据的哈希值,计算此格式下的证明语句。
-
验证过程: 验证证明语句的流程,接收如下 验证过程输入:
-
attStmt:证明语句结构
-
authenticatorData:被声明用于证明的 认证器数据
-
clientDataHash:序列化客户端数据的哈希值
该过程返回:
-
最初指定的证明语句格式列表见§ 8 已定义的证明语句格式。
6.5.3. 证明类型
WebAuthn 支持多种证明类型,这些定义了证明语句及其信任模型的语义:
注意:本规范并未专门定义用于表述认证器所用证明类型的数据结构。Relying Party在进行证明语句验证时(即调用 navigator.credentials.create()
时选择的证明传递不是
none,并验证收到的证明语句),会在验证过程中确定所采用的证明类型。参见 § 8 已定义的证明语句格式相关“验证过程”小节,以及 § 14.4.1 证明隐私性。除 Self、None 之外,本节所有证明类型都要求 Relying Party 校验信任路径,匹配到 §7.1 注册新凭据,第 23
步 所述可接受的根证书。
区分这些证明类型主要用于判断证明是否符合Relying Party的安全策略。
- 基本证明 (Basic)
-
基本证明 [UAFProtocol] 情况下,认证器的证明密钥对是面向具体认证器“型号”分配的,即一批认证器共用。因此相同/近似型号认证器通常共享 证明密钥对。详见 § 14.4.1 证明隐私性。
基本证明也称为 批量证明。
- 自我证明 (Self)
-
自我证明(又称代理基本证明 [UAFProtocol])情况下,认证器没有专门的证明密钥对,而是直接用凭据私钥生成证明签名。一般来说,没有有效保护证明私钥措施的认证器采用此类型。
- 证明 CA (AttCA)
-
此情形下,认证器基于可信平台模块(TPM),持有认证器专用“背书密钥”(EK),该密钥用于与可信第三方,即证明 CA [TCG-CMCProfile-AIKCertEnroll] 安全通信。认证器可以生成多对证明身份密钥对(AIK),并为每对向证明 CA 申请签发证书。该方案可将 EK(全局唯一标识)暴露范围仅限于证明 CA。每个认证器生成的公钥凭据都可以单独申请 AIK,并通过证明证书传递给 Relying Party。
注意:此模式下常见多张证明证书,最后申请的那张为“活跃”证书。
- 匿名化 CA (AnonCA)
-
此情形下,认证器使用匿名化 CA 动态为每个凭据生成证明证书,使向 Relying Party 传递的 证明语句不包含可唯一标识信息(如用于追踪等)。
注意:证明语句用以传递 证明的 AttCA、AnonCA 类型与 Basic 类型语句结构完全一致,三者通常仅靠外部已知证书内容区分。
- 无证明语句 (None)
-
此时不存在任何证明信息。参见 § 8.7 None 证明语句格式。
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 填充 Map // [ * any ] ; attStmt 也可以为数组 ) }
6.5.5. Packed Attestation、FIDO U2F Attestation 与断言签名的签名格式
-
对于 COSEAlgorithmIdentifier -7 (ES256) 及其它基于 ECDSA 的算法,
sig值必须按 [RFC3279] 第 2.2.3 节定义,以 ASN.1 DER Ecdsa-Sig-Value 形式编码。例: 30 44 ; SEQUENCE (68 字节) 02 20 ; INTEGER (32 字节) | 3d 46 28 7b 8c 6e 8c 8c 26 1c 1b 88 f2 73 b0 9a | 32 a6 cf 28 09 fd 6e 30 d5 a7 9f 26 37 00 8f 54 02 20 ; INTEGER (32 字节) | 4e 72 23 6e a3 90 a9 a1 7b cf 5f 7a 09 d6 3a b2 | 17 6c 92 bb 8e 36 c0 41 98 a2 7b 90 9b 6e 8f 13
建议新定义的证明格式不使用 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 Relying Party 操作
一个 注册
或 认证流程 由
WebAuthn
Relying Party 分别创建一个 PublicKeyCredentialCreationOptions
或 PublicKeyCredentialRequestOptions
对象开始,这两个对象负责编码 流程 的参数。Relying Party
应确保在此阶段不泄漏敏感信息;详情见 § 14.6.2 用户名枚举。
成功执行 create()
或 get()
后,Relying Party 的脚本将从客户端收到一个
PublicKeyCredential
,其中包含 AuthenticatorAttestationResponse
或 AuthenticatorAssertionResponse
结构。
然后必须将该结构的内容传递给 Relying Party
服务器,传递方式超出本规范范围。此节说明 Relying
Party 在收到这些结构后需执行的操作。
7.1. 注册新凭据
为执行一次 注册流程,Relying Party 必须按如下步骤操作:
-
令 options 为新的
CredentialCreationOptions结构体,根据 Relying Party 对该流程的需求进行设置。 令 pkOptions 为options.。publicKey -
调用
navigator.credentials.create()并将 options 作为参数传入。 令 credential 为成功解析的 Promise 结果。 如果 Promise 被拒绝,需以用户可见错误中止流程,或根据已知上下文引导用户操作。例如,如果 Promise 拒绝时错误码等价于 "InvalidStateError", 可提示用户换用其他 认证器。 关于不同错误情境及相关原因,详见 § 6.3.2 authenticatorMakeCredential 操作。 -
令 response 为
credential.。 若 response 不是responseAuthenticatorAttestationResponse实例,则以用户可见错误中止流程。 -
令 clientExtensionResults 为调用
credential.的结果。getClientExtensionResults() -
令 JSONtext 为对
response.的值执行 UTF-8 解码 的结果。clientDataJSON注释: 只要实现的 UTF-8 解码 能得到与标准算法一致的结果,即可采用,尤其要去除任何前导字节顺序标记(BOM)。
-
令 C,即 客户端数据,为对 JSONtext 运行特定实现的 JSON 解析器的结果。
注释: C 可以是任何特定实现的数据结构表示,只要本算法要求的各分量可被引用即可。
-
验证
C.的值为typewebauthn.create。 - 验证
C.的值是否为 Relying Party 期望的 origin。 参考 § 13.4.9 验证凭据来源 获得指导。origin -
若
C.存在且为crossOrigintrue, 验证 Relying Party 是否期望该凭据是在一个与其祖先非同源的 iframe 内创建的。 -
若
C.存在:topOrigin-
验证 Relying Party 是否期望该凭据是在一个与其祖先非同源的 iframe 内创建的。
-
验证
C.的值是否与 Relying Party 期望嵌入页面的 origin 匹配。 参考 § 13.4.9 验证凭据来源topOrigin
-
-
令 hash 为使用 SHA-256 算法对
response.进行哈希运算得到的结果。clientDataJSON -
对
attestationObject字段进行 CBOR 解码以获得 attestation 声明格式 fmt、认证器数据 authData,以及 attestation 声明 attStmt。 -
验证 authData 中
rpIdHash是否为 Relying Party 期望的 RP ID 的 SHA-256 哈希值。 -
若
options.未被设置为mediationconditional, 则验证 authData 中UP位是否被设置。 -
若 Relying Party 要求该注册流程进行 用户验证, 验证 authData 中
UV位是否被设置。 -
若 Relying Party 以凭据的 备份可用性 指导其用户体验或策略,应评估 authData 中 BE 位。
-
若 Relying Party 以凭据的 备份状态 指导其用户体验或策略,应评估 authData 中 BS 位。
-
验证 authData 内 凭据公钥 的 "alg" 参数是否与
pkOptions.中某条目的pubKeyCredParamsalg属性一致。 -
通过对 fmt 与支持的 WebAuthn Attestation Statement Format Identifier 值集合进行 USASCII 区分大小写匹配,确定 attestation 声明格式。 WebAuthn Attestation Statement Format Identifier 已注册值的最新列表由 IANA "WebAuthn Attestation Statement Format Identifiers" 注册表 [IANA-WebAuthn-Registries] 维护, 该注册表由 [RFC8809] 建立。
-
按照 fmt 的 attestation 声明格式 的 验证流程,使用
attStmt、authData 和 hash
验证 attStmt 是否为正确的 attestation 声明,并传递有效的 attestation 签名。
注释: 每种 attestation 声明格式 都定义了自己的 验证流程。详见 § 8 已定义的 attestation 声明格式,以及 [IANA-WebAuthn-Registries] 最新清单。
- 验证成功后,从可信来源或策略中获得该 attestation 类型和 attestation
声明格式 fmt
的可接受信任锚(即 attestation 根证书)列表。例如,通过 FIDO Metadata Service [FIDOMetadataService]
,并利用 authData 中
aaguid字段attestedCredentialData获得相关信息。 -
利用验证流程(见第21步)的输出评估 attestation 的可信度,如下:
-
若为 无 attestation,验证 None attestation 是否符合 Relying Party 策略要求。
-
若采用 自签名 attestation,验证 自签名 attestation 是否被 Relying Party 策略接受。
-
否则,使用 验证流程 返回的 X.509 证书作为 attestation 信任路径,验证 attestation 公钥是否能正确链至可接受根证书,或者本身就是可接受的证书 (即该证书和上一步获得的根证书可相同)。
若 attestation 声明不可信,Relying Party 应使 注册流程 失败。
注释: 但若策略允许,Relying Party 可以登记此 凭据 ID 和凭据公钥, 但将其视为 自签名 attestation(见 § 6.5.3 attestation 类型)。此时,Relying Party 等于声明 对于该 公钥凭据 并无属某认证器型号的密码学证明。 参见 [FIDOSecRef] 及 [UAFProtocol] 的详细讨论。
-
-
验证
credentialId的长度 ≤ 1023 字节。超出此长度的凭据 ID 应使 RP 使 注册流程 失败。 -
验证
credentialId未被任何用户注册。若credentialId已存在,则 Relying Party 应使 注册流程 失败。注释: Relying Party 拒绝重复 凭据 ID 的理由如下: 凭据 ID 的熵足够高,偶然冲突的可能性极小。 但 非自签名 attestation 并未通过自签名明确证明 凭据私钥 在 注册 时真实可用。 因此攻击者若获得了用户的 凭据 ID 及 凭据公钥(实现方式多样), 可能尝试冒名注册,若被接受且原凭据可发现,则受害者下次登录将进入攻击者账户,数据可能被攻击者获取。
-
令 credentialRecord
为一份新 凭据记录,其内容如下:
- type
-
credential.type - id
-
credential.或idcredential.,由 Relying Party 选择格式。rawId - publicKey
-
authData 中的 凭据公钥。
- signCount
-
authData.signCount - uvInitialized
- transports
-
response.的返回值。getTransports() - backupEligible
- backupState
新的 凭据记录 还可以包含以下可选内容:
- attestationObject
-
response.attestationObject - attestationClientDataJSON
-
response.clientDataJSON
Relying Party 还可以根据需要包含任何额外的 信息项。 示例(非规范性):Relying Party 可以让用户为凭据设置“昵称”,以便用户在账户设置时分辨当前 凭据 是绑定到哪个 认证器。
-
按需处理
clientExtensionResults 里的 客户端扩展输出,
以及 authData 中
扩展里的 认证器扩展输出, 具体由 Relying Party 决定。 每个 扩展 的处理可能有明确规范,也可能仅由 Relying Party 决定如何处理。 Relying Party 可以选择忽略部分或全部扩展输出。客户端 可以设置额外的 认证器扩展 或 客户端扩展 ,这样会导致在 认证器扩展输出 或 客户端扩展输出 中出现 Relying Party 在
pkOptions.未请求的值。 Relying Party 必须做好处理这类情况的准备, 可选择忽略这些未请求的扩展或直接拒绝 attestation。Relying Party 可结合本地策略和使用的扩展来决定。extensions由于所有扩展对于 客户端 和 认证器 均为可选,Relying Party 还必须处理所有或部分请求扩展未生效的情况。
-
若上述所有步骤均通过, 将 credentialRecord 存储到
pkOptions.所指代的 用户账户中,并按需求继续 注册流程; 否则,使 注册流程 失败。user若 Relying Party 未因此失败 注册流程, 则视为接受没有任何凭据是由特定 认证器 生成的密码学证明。 Relying Party 可以将该凭据等价视为 无 attestation(参见 § 6.5.3 attestation 类型)。 参见 [FIDOSecRef] 与 [UAFProtocol] 的详细讨论。
验证 attestation object 要求 Relying Party 能可靠确定 第22步 里的信任锚, 且如涉及证书,Relying Party 必须能获取中间 CA 证书的状态信息。 如果客户端未提供 attestation 证书链,Relying Party 也必须能自行构建 attestation 证书链。
7.2. 验证认证断言
为了执行一次 认证仪式,Relying Party 必须按以下步骤进行:
-
令 options 为新的
CredentialRequestOptions结构体,并配置为满足 Relying Party 对此次仪式的需求。令 pkOptions 为options.。publicKey -
调用
navigator.credentials.get()并将 options 作为参数传入。令 credential 为成功解析的 promise 的结果。如果 promise 被拒绝,则以用户可见的错误中止该过程,或根据被拒绝 promise 的上下文适当引导用户体验。关于不同错误上下文及其成因,详见 § 6.3.3 authenticatorGetAssertion 操作。 -
令 response 为
credential.。如果 response 不是responseAuthenticatorAssertionResponse的实例,则以用户可见的错误中止该过程。 -
令 clientExtensionResults 为调用
credential.的结果。getClientExtensionResults() -
如果
pkOptions.不为空,验证allowCredentialscredential.标识的是 public key credentials 中列出的其中一个,idpkOptions.。allowCredentials -
识别当前正在认证的用户,令 credentialRecord 为对应 凭证记录 的 credential:
-
令 cData、authData 和 sig 分别为 response 的
clientDataJSON、authenticatorData和signature的值。 -
令 JSONtext 为对 cData 进行 UTF-8 解码 的结果。
注意: 只要结果与 UTF-8 解码 算法一致,任何实现的 UTF-8 解码 都是可接受的。尤其要去除任何前导的字节顺序标记(BOM)。
-
令 C(声称用于签名的 客户端数据)为执行特定实现的 JSON 解析器解析 JSONtext 的结果。
注意:C 可以是任意特定实现的数据结构,只要 C 的各组成部分可被引用,满足本算法需求即可。
-
验证
C.的值为字符串typewebauthn.get。 - 验证
C.的值为 Relying Party 期望的 源。见 § 13.4.9 证书源验证。origin -
如果
C.存在且为crossOrigintrue,验证 Relying Party 期望此凭证用于非 同源 的 iframe 内。 -
如果
C.存在:topOrigin-
验证 Relying Party 期望该凭证用于非 同源 的 iframe 内。
-
验证
C.的值与 Relying Party 期望被包含在的页面源匹配。见 § 13.4.9 证书源验证。topOrigin
-
-
验证 authData 内的
rpIdHash是否为 RP ID 的 SHA-256 哈希值,且该 RP ID 为 Relying Party 期望值。注意: 如果使用 appid 扩展,本步骤需要特殊逻辑。见 § 10.1.1 FIDO AppID 扩展 (appid)。
-
判断本次断言是否需要 用户验证。只有当
pkOptions.设为userVerificationrequired时,才应要求 用户验证。 -
如果凭证 备份状态 被 Relying Party 业务逻辑或策略采纳,令 currentBe 和 currentBs 为 authData 中 BE 和 BS 位的值。并将 currentBe 和 currentBs 与
credentialRecord.backupEligible及credentialRecord.backupState比较:-
如果
credentialRecord.backupEligible已设置,验证 currentBe 已设置。 -
如果
credentialRecord.backupEligible未设置,验证 currentBe 未设置。 -
应用 Relying Party 策略(如有)。
注意: 参见 § 6.1.3 凭证备份状态,了解 Relying Party 如何处理 BS 标志。
-
-
令 hash 为 cData 以 SHA-256 进行哈希后的结果。
-
使用
credentialRecord.publicKey,验证 sig 是否为 authData 和 hash 二进制拼接的有效签名。注意: 此步骤与 FIDO U2F 认证器生成的签名兼容。见 § 6.1.2 FIDO U2F 签名格式兼容性。
-
如果 authData.
signCount非零,或credentialRecord.signCount非零,则执行如下子步骤:-
如果 authData.
signCount:- 大于
credentialRecord.signCount: - 签名计数器有效。
- 小于或等于
credentialRecord.signCount: -
这表明认证器可能已被克隆,但并非确切证据。例如,这可能意味着:
-
可能存在两个或更多 凭证私钥 副本,并被并行使用。
-
认证器发生了故障。
-
存在竞争条件,Relying Party 按非认证器生成顺序处理了断言响应。
Relying Party 应结合自身业务特性,将此信息纳入风险评估。是否在本情况下在下方
credentialRecord.signCount更新,或直接失败 认证仪式 由 Relying Party 自行决定。更多签名计数器说明,参见 § 6.1.1 签名计数器说明。
-
- 大于
-
-
按Relying Party 需要,处理
clientExtensionResults 的 客户端扩展输出和 authData 内
extensions的 认证器扩展输出。 不同 扩展 可有具体流程,也可由 Relying Party 自定处理方法。Relying Party 可忽略全部或部分扩展输出。客户端 可设置附加 认证器扩展 或 客户端扩展,导致出现 认证器扩展输出 或 客户端扩展输出,这些值并非 Relying Party 在
pkOptions.请求的。Relying Party 必须能处理这种情况,可以选择忽略或拒绝断言。可以结合本地策略和实际使用扩展自行决定。extensions所有扩展对 客户端 和 认证器 都是可选的,Relying Party 也要能应对未命中全部或部分请求扩展的情形。
-
用新的状态值更新
credentialRecord:
-
将
credentialRecord.backupState更新为 currentBs 的值。 -
如果
credentialRecord.uvInitialized为false,则更新为 authData 内 UV 位的值。此步骤建议需经附加的 认证因子 授权,如 WebAuthn 用户验证;未授权则略过此步骤。
如果 Relying Party 还有更进一步的安全校验,则应在这些 WebAuthn 认证仪式检查后再执行上述状态更新。
-
若以上步骤全部成功,则继续后续 认证仪式;否则认证失败。
8. 定义的证明声明格式
WebAuthn 支持可插拔的证明声明格式。本节定义了一组初始格式。
8.1. 证明声明格式标识符
证明声明格式由一个字符串进行标识,该字符串称为 证明声明格式标识符,由证明声明格式的创建者选择。
证明声明格式标识符应在 IANA 建立的 “WebAuthn Attestation Statement Format Identifiers” 注册表 [IANA-WebAuthn-Registries] 中注册,见 [RFC8809]。 所有注册的证明声明格式标识符彼此唯一。
未注册的证明声明格式标识符应采用小写反向域名命名方式,并使用开发者已注册的域名,以确保标识符唯一。所有证明声明格式标识符长度不得超过 32 个八位字节,且只能包含可打印的美国 ASCII 字符,不包括反斜杠和双引号,即与 [RFC5234] 所定义的 VCHAR 一致,但不含 %x22 和 %x5c。
注意:这意味着基于域名的证明声明格式标识符仅可包含 LDH 标签[RFC5890]。
实现必须严格区分大小写地匹配 WebAuthn 证明声明格式标识符。
若证明声明格式可能存在多个版本,建议其标识符中包含版本号。实际上,不同的版本即被视为不同的格式,例如 packed2 代表 § 8.2 Packed Attestation Statement Format 的新版本。
下列小节介绍目前定义并注册的证明声明格式及其标识符。 已注册的证明声明格式标识符的最新列表由 IANA “WebAuthn Attestation Statement Format Identifiers” 注册表维护,见 [IANA-WebAuthn-Registries],依据 [RFC8809] 设立。
8.2. Packed 证明声明格式
这是 WebAuthn 优化的证明声明格式。它采用极其紧凑但可扩展的编码方式,适用于资源有限(如安全元件)的认证器实现。
- 证明声明格式标识符
-
packed
- 支持的证明类型
- 语法
-
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 格式编码的认证(证明)证书。
- 签名过程
-
此证明声明格式的签名过程类似于 断言签名生成流程。
- 验证过程
-
给定验证输入 attStmt、authenticatorData 和 clientDataHash,验证过程如下:
-
确认 attStmt 为符合上述语法的有效 CBOR,并对其进行 CBOR 解码提取字段。
-
若 x5c 存在:
-
用 attestnCert 的公钥及 alg 算法,验证 sig 是否为 authenticatorData 与 clientDataHash 拼接的有效签名。
-
验证 attestnCert 是否满足 § 8.2.1 Packed 证明证书要求。
-
若 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. Packed 证明声明的证书要求
证明证书必须包含以下字段/扩展:
-
版本号必须设为 3(ASN.1 INTEGER 值为 2)。
-
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。 该扩展不得标记为 critical。鉴于Relying Party 可能不知该根证书是否用于多个认证器型号,因此建议 Relying Party 检查该扩展是否存在,如有则校验其与 证明对象 所示 AAGUID 一致。
X.509 Extension 内值为 OCTET STRING,实际应套两层 OCTET STRING 才合规。
-
Basic Constraints 扩展必须将 CA 设置为
false。
可选地,还可包含 Authority Information Access (AIA) 扩展(带 id-ad-ocsp 的条目)及 CRL Distribution Point 扩展 [RFC5280]。
由于很多证明证书的状态可由认证器元数据服务查询,例如 FIDO Metadata Service [FIDOMetadataService]。
特定认证器型号的固件版本可通过 OID 为
1.3.6.1.4.1.45724.1.1.5(id-fido-gen-ce-fw-version)的扩展区分。若存在,该属性值为递增的非负整数,各新固件版本递增。不得标记为
critical。
下例为含所列扩展 OID 和必填字段的证明证书:
-----BEGIN CERTIFICATE-----MIIBzTCCAXOgAwIBAgIUYHS3FJEL/JTfFqafuAHvlAS+hDYwCgYIKoZIzj0EAwIw QTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC1dlYkF1dGhuIFdHMRwwGgYDVQQDDBNF eGFtcGxlIEF0dGVzdGF0aW9uMCAXDTI0MDEwMzE3NDUyMVoYDzIwNTAwMTA2MTc0 NTIxWjBBMQswCQYDVQQGEwJVUzEUMBIGA1UECgwLV2ViQXV0aG4gV0cxHDAaBgNV BAMME0V4YW1wbGUgQXR0ZXN0YXRpb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC AATDQN9uaFFH4BKBjthHTM1drpb7gIuPod67qyF6UdL4qah6XUp6tE7Prl+DfQ7P YH9yMOOcci3nr+Q/jOBaWVERo0cwRTAhBgsrBgEEAYLlHAEBBAQSBBDNjDlcJu3u 3mU7AHl9A8o8MBIGCysGAQQBguUcAQEFBAMCASowDAYDVR0TAQH/BAIwADAKBggq hkjOPQQDAgNIADBFAiA3k3aAUVtLhDHLXOgY2kRnK2hrbRgf2EKdTDLJ1Ds/RAIh AOmIblhI3ALCHOaO0IO7YlMpw/lSTvFYv3qwO3m7H8Dc -----END CERTIFICATE-----
以上属性在证书中结构如下:
30 21 -- SEQUENCE
06 0B 2B 06 01 04 01 82 E5 1C 01 01 04 -- OID 1.3.6.1.4.1.45724.1.1.4
04 12 -- OCTET STRING
04 10 -- OCTET STRING
CD 8C 39 5C 26 ED EE DE -- AAGUID cd8c395c-26ed-eede-653b-00797d03ca3c
65 3B 00 79 7D 03 CA 3C
30 12 -- SEQUENCE
06 0B 2B 06 01 04 01 82 E5 1C 01 01 05 -- OID 1.3.6.1.4.1.45724.1.1.5
04 03 -- OCTET STRING
02 01 -- INTEGER
2A -- 固件版本:42
8.2.2. 企业 Packed 证明声明的证书要求
OID 为 1.3.6.1.4.1.45724.1.1.2(id-fido-gen-ce-sernum)的扩展可选地出现在企业用途的 packed
证明里。如存在,该扩展须针对特定 AAGUID,为每台设备指示唯一的 octet string 值。此值须在恢复出厂设置后保持不变,但可与设备其它序列号或硬件标识符不同。本扩展不得标记为 critical,值类型为
OCTET STRING。非企业证明不得含本扩展。
8.3. TPM 证明声明格式
此证明声明格式一般用于以可信平台模块(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设为 attToBeSigned 的摘要,哈希算法由 “alg” 指定。(如 "RS256" 则为 SHA-256 摘要。)pubArea 设为凭据公钥的公有域(TPMT_PUBLIC 结构),certInfo 字段(TPMS_ATTEST 结构)即签名输出参数同名字段,sig 字段为上步所得签名。
注意:若通过 TPM2_ReadPublic 命令读取 pubArea,其返回 TPM2B_PUBLIC 结构(2 字节长度加 TPMT_PUBLIC)。须去除头两字节长度再填入 pubArea。
- 验证过程
-
给定验证输入 attStmt、authenticatorData 和 clientDataHash,验证过程如下:
确认 attStmt 为有效 CBOR,符合上文语法,并对其 CBOR 解码提取字段。
确认 pubArea 的
parameters与unique字段指定的公钥,与 authenticatorData 内credentialPublicKey以及attestedCredentialData一致。拼接 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 的 nameAlg 计算的合法 Name。见 [TPMv2-Part1] 16 节。注意:TPM 总以 pubArea 的 nameAlg 生成
name。注意:“标准证明结构” [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。 -
Authority Information Access (AIA) 扩展(带
id-ad-ocsp条目)和 CRL Distribution Point 扩展 [RFC5280] 都是可选的,因为许多证明证书的状态可通过元数据服务获得。例如参见 FIDO Metadata Service [FIDOMetadataService]。
8.4. Android Key 证明声明格式
当相关认证器是 Android "N" 或更高版本上的平台认证器时,证明声明基于 Android 密钥证明。此时,证明声明由安全操作环境中的组件生成,但证明用认证器数据是在该环境外生成的。WebAuthn Relying Party 需检查声明用于证明的认证器数据与证明证书拓展数据的字段一致性。
- 证明声明格式标识符
-
android-key
- 支持的证明类型
- 语法
-
Android Key 证明声明即为 Android 证明声明本身,由一系列 DER 编码的 X.509 证书组成。详见Android 官方开发文档。其语法定义如下:
$$attStmtType //= ( fmt: "android-key", attStmt: androidStmtFormat ) androidStmtFormat = { alg: COSEAlgorithmIdentifier, sig: bytes, x5c: [ credCert: bytes, * (caCert: bytes) ] } - 签名过程
-
令 authenticatorData 表示证明用的认证器数据,clientDataHash 表示序列化客户端数据的哈希。
调用
keyStore.getCertificateChain(myKeyUUID)请求 Android Key Attestation,并将 clientDataHash 作为挑战值传入(如通过 setAttestationChallenge)。x5c 设为返回值。认证器通过拼接 authenticatorData 和 clientDataHash 后用凭据私钥签名得到 sig,alg 设为签名格式的算法。
- 验证过程
-
给定验证输入 attStmt、authenticatorData 和 clientDataHash,验证过程如下:
-
确认 attStmt 是符合上述语法的有效 CBOR,并进行 CBOR 解码提取字段。
-
用 x5c 的首个证书的公钥和 alg 指定算法,验证 sig 是否为 authenticatorData 与 clientDataHash 拼接的有效签名。
-
校验 x5c 第一张证书公钥与 authenticatorData 的
credentialPublicKey一致。 -
校验证明证书拓展数据中的
attestationChallenge字段等于 clientDataHash。 -
使用证明证书拓展数据的授权列表(authorization list)做如下验证:
-
8.4.1. Android Key 证明声明证书要求
Android Key Attestation 证明证书的Android Key 证明证书拓展数据的 OID 为
1.3.6.1.4.1.11129.2.1.17,其结构定义详见Android
官方文档。
8.5. Android SafetyNet 证明声明格式
注意:本格式已弃用,预计将在将来版本中移除。
当认证器是某些 Android 平台上的平台认证器时,证明声明可能基于 SafetyNet API。此时认证器数据完全由调用 SafetyNet API 的应用(通常是 Android 平台上的应用)控制,证明声明则提供关于平台健康和调用应用身份的信息(详见 SafetyNet 文档)。
- 证明声明格式标识符
-
android-safetynet
- 支持的证明类型
- 语法
-
Android Attestation 声明的语法如下:
$$attStmtType //= ( fmt: "android-safetynet", attStmt: safetynetStmtFormat ) safetynetStmtFormat = { ver: text, response: bytes }各字段含义如下:
- ver
-
提供 SafetyNet API 的 Google Play 服务的版本号。
- response
-
SafetyNet API 的 getJwsResult() 返回的UTF-8 编码结果,此值为 JWS [RFC7515] 对象(详见 SafetyNet 在线文档),采用紧凑序列化格式。
- 签名过程
-
令 authenticatorData 表示证明用的认证器数据,clientDataHash 表示序列化客户端数据的哈希。
拼接 authenticatorData 和 clientDataHash,对其执行 SHA-256 哈希,取结果为 attToBeSigned。
请求 SafetyNet attestation,将 attToBeSigned 作为 nonce。response 设为结果,ver 设为认证器内的 Google Play 服务版本号。
- 验证过程
-
给定验证输入 attStmt、authenticatorData 和 clientDataHash,验证过程如下:
-
确认 attStmt 是符合上述语法的有效 CBOR,并进行解码提取字段。
-
按 SafetyNet 在线文档 验证 response 为 ver 版本的有效 SafetyNet 响应。目前仅有一种 SafetyNet 响应格式,ver 为将来扩展预留。
-
验证 response 的 JWS 载荷中
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,长度 32 字节)。
按 [FIDO-U2F-Message-Formats] 4.3 节要求生成注册响应消息,application parameter 设为该凭据所作用域限定到的RP ID 的 SHA-256 哈希,challenge parameter 设为 clientDataHash,key handle parameter 设为凭据的 凭据 ID。将注册响应消息的原始签名字节(不含 user public key、key handle 和证明证书)设为 sig,证明公钥的证书设为 x5c。
- 验证过程
-
给定验证输入 attStmt、authenticatorData 和 clientDataHash,验证过程如下:
-
确认 attStmt 是符合上述语法的有效 CBOR,并解码提取字段。
-
检查 x5c 仅有一个元素,将其设为 attCert,再取 certificate public key 为 attCert 对应的公钥。若该公钥不是 P-256 曲线上的 EC 公钥,终止并返回错误。
-
从 authenticatorData 取出 rpIdHash,并从 authenticatorData.
attestedCredentialData取 credentialId 和 credentialPublicKey。 -
将 COSE_KEY 格式的 credentialPublicKey(详见 RFC9052 7 节)转换为原始 ANSI X9.62 公钥格式(见 FIDO-Registry 3.6.2 节)。
-
取得 "-2" 键对应值 x(x 坐标),确认其为 32 字节。若大小不对或未找到,终止并报错。
-
取得 "-3" 键对应值 y(y 坐标),确认其为 32 字节。若大小不对或未找到,终止并报错。
-
用
0x04 || x || y拼接为 publicKeyU2F。注意: 这意味着未压缩 ECC 公钥格式。
-
-
令 verificationData 为
0x00 || rpIdHash || clientDataHash || credentialId || publicKeyU2F(见 4.3 节)。 -
用 certificate public key 和 verificationData,按 [SEC1] 4.1.4 节,使用 SHA-256 验证 sig。
-
8.7. None 证明声明格式
None 证明声明格式用于当WebAuthn Relying Party声明不希望接收证明信息时,替换任意认证器返回的证明声明。详见§ 5.4.7 Attestation Conveyance Preference Enumeration (enum AttestationConveyancePreference)。
- 证明声明格式标识符
-
none
- 支持的证明类型
- 语法
-
none 证明声明格式语法如下:
$$attStmtType //= ( fmt: "none", attStmt: emptyMap ) emptyMap = {} - 签名过程
-
返回上述固定证明声明。
- 验证过程
8.8. Apple 匿名声明格式
该声明格式仅由 Apple 用于支持 WebAuthn 的某些类型的 Apple 设备。
- 声明格式标识符
-
apple
- 支持的声明类型
- 语法
-
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 表示该证书。此证书不仅作为声明证明,且包含的 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,其验证流程如下:
-
对 attStmt 中的每个 subStmt, 执行与 声明格式标识符
subStmt.fmt对应的验证流程,使用 流程输入 subStmt、authenticatorData 和 clientDataHash。若任一 subStmt 验证失败,可依Relying Party 策略决定处理结果。
-
若足够多(由Relying Party 策略决定)项目在 attStmt 中通过验证, 则返回由所有通过的验证流程输出组成的组合实现相关值。
-
9. WebAuthn 扩展
生成公钥凭据及请求、生成认证断言的机制(定义于§ 5 Web Authentication API)可通过扩展进行适应。每种情形通过定义注册扩展 及/或 认证扩展实现。
每个扩展都是客户端扩展,意味着扩展涉及与客户端的通信与处理。客户端扩展定义了以下步骤和数据:
-
navigator.credentials.create()的登记扩展请求参数及返回值,适用于 注册扩展。 -
navigator.credentials.get()的认证扩展请求参数及返回值,适用于认证扩展。
在创建公钥凭据或请求认证断言时,
WebAuthn
Relying Party 可请求使用一组扩展。若客户端和/或WebAuthn 认证器支持,这些扩展将在请求操作时被调用。Relying Party 通过 get()
(用于认证扩展)或 create()
(用于注册扩展)调用时,为每个扩展发送 客户端扩展输入 给 客户端。客户端 对所支持扩展执行客户端扩展处理,并按每个扩展规范用 扩展标识符 和 客户端扩展输出补充 客户端数据。
扩展也可为认证器扩展,即扩展涉及认证器通信及处理。认证器扩展定义了如下流程及数据:
-
authenticatorMakeCredential 的扩展请求参数与返回值,适用于 注册扩展。
-
authenticatorGetAssertion 的扩展请求参数与返回值,适用于 认证扩展。
对于认证器扩展,作为客户端扩展处理的一部分,客户端还需为每个扩展创建 CBOR 格式的 认证器扩展输入 值(通常基于对应的
客户端扩展输入),并通过
create()
(用于注册扩展)或
get()
(用于认证扩展)传递给认证器。这些 认证器扩展输入 用 CBOR 表示,并以 扩展标识符 作为名称、相应的 认证器扩展输入 作为值的键值对形式传递。认证器对其支持的扩展执行进一步处理并返回每个扩展的 CBOR 认证器扩展输出。由于 认证器扩展输出随 认证器数据 签名返回,认证器扩展可另指定未签名扩展输出,例如当输出本身需依赖 认证器数据时。
作为客户端扩展处理的一部分,要用 认证器扩展输出 及 未签名扩展输出 构造 客户端扩展输出。
所有 WebAuthn 扩展 对于客户端和认证器来说都是可选的。因此,Relying Party 请求的扩展可能被浏览器或操作系统忽略而不会传给认证器,也可能被认证器忽略。 扩展被忽略不属于 WebAuthn API 流程失败,因此 Relying Party 使用扩展时,必须能正确处理部分或全部扩展被忽略的情况。
所有 WebAuthn 扩展 必须制定,使客户端与认证器不支持该扩展时不会危及用户安全或隐私。 例如,若扩展需要客户端处理,可设计为仅做格式转发(如简单地把 客户端扩展输入 从 JSON 转为 CBOR),经认证器处理后无语义效果,该扩展即被安全地忽略。由于扩展均为可选,不会导致 API 调用失败。
IANA“WebAuthn 扩展标识符”注册表 [IANA-WebAuthn-Registries](由 [RFC8809] 建立)可用于查询最新注册的 WebAuthn 扩展 的列表。
9.1. 扩展标识符
扩展通过字符串标识,称为扩展标识符,由扩展定义者选择。
扩展标识符应在 IANA“WebAuthn 扩展标识符”注册表 [IANA-WebAuthn-Registries](由 [RFC8809] 建立)进行注册。 所有已经注册的扩展标识符应保证全局唯一。
未注册的扩展标识符亦应尽量全球唯一,例如包含定义实体前缀,如 myCompany_extension。
所有扩展标识符最长32字节,仅包含可打印 USASCII 字符, 不允许反斜线和双引号,即为 [RFC5234] VCHAR 集合中的可打印字符,但不包括 %x22 和 %x5c。实现需区分大小写比对扩展标识符。
有多个版本的扩展,标识符建议含版本,如 myCompany_extension_01,不同版本视为不同扩展。
§ 10 已定义扩展给出了额外的扩展与其标识符。详见 IANA“WebAuthn Extension Identifiers”注册表 [IANA-WebAuthn-Registries] 以获取最新的注册扩展标识符。
9.2. 扩展定义方法
扩展定义必须指定 扩展标识符、客户端扩展输入(通过 get()
或 create()
传递),客户端扩展处理规则和 客户端扩展输出值。
如扩展需认证器通信(即为 认证器扩展),还须指定 CBOR 认证器扩展输入参数(通过 authenticatorGetAssertion
或 authenticatorMakeCredential 调用),认证器扩展处理规则以及 CBOR 认证器扩展输出值。
扩展可指定未签名扩展输出。
客户端处理的 客户端扩展 必须返回 客户端扩展输出,以便 WebAuthn Relying Party 可确认扩展已被客户端支持。认证器处理的扩展则必须返回 认证器扩展输出,以便 Relying Party 明确扩展被认证器支持。若扩展无需返回其它结果,推荐定义为返回 JSON 布尔 客户端扩展输出 结果(true 表示扩展已被理解并处理)。类似,未定义返回值的 认证器扩展 应返回 CBOR 布尔 认证器扩展输出(true 表示扩展被处理)。
9.3. 扩展请求参数的拓展
扩展定义一个或两个请求参数。客户端扩展输入
(可编码为 JSON 的值)由 WebAuthn Relying Party 通过 get()
或 create()
方法传递到客户端;
对于认证器扩展,CBOR 格式的认证器扩展输入会在流程中由客户端传递给认证器。
Relying Party 请求扩展并设置其 客户端扩展输入,方式是在 extensions
选项中传递对应 扩展标识符
键及值(客户端扩展输入),无论是在 create()
或 get()
调用中。
注意: 其它文档可能指定扩展输入并非严格用扩展标识符作键,但对于新扩展仍然适用上述规范。
var assertionPromise= navigator. credentials. get({ publicKey: { // 省略其它成员 extensions: { // “entry key”为“webauthnExample_foobar”扩展, // 其值为含两个输入参数的对象: "webauthnExample_foobar" : { foo: 42 , bar: "barfoo" } } } });
扩展定义必须说明其 客户端扩展输入 的合法值。客户端应忽略无效输入的扩展。如扩展无需 Relying Party 参数,建议定义为布尔型客户端参数,true
表示请求使用该扩展。
仅影响客户端处理的扩展无需定义 认证器扩展输入。
涉及认证器处理的扩展,必须说明如何从 客户端扩展输入 生成 认证器扩展输入,
并就CDDL类型
AuthenticationExtensionsAuthenticatorInputs
和
AuthenticationExtensionsAuthenticatorOutputs
定义 $$extensionInput 和 $$extensionOutput 的组套新分支,采用扩展标识符为键。
参数为布尔型的扩展,其 认证器扩展输入 也应为常量布尔 true(CBOR 主类型7,值21)。
以下示例定义了标识符为 webauthnExample_foobar 的扩展,接收无符号整数作为 认证器扩展输入,返回一组字节串作为
认证器扩展输出:
$$extensionInput //= ( webauthnExample_foobar : uint) $$extensionOutput //= ( webauthnExample_foobar : [ + bytes] )
由于部分认证器通过低带宽链路(如蓝牙低能耗或 NFC)通信,建议定义的认证器参数尽可能小。
9.4. 客户端扩展处理
扩展可定义在凭据创建或断言生成时 客户端 的附加处理流程。客户端扩展输入 用作此客户端处理的输入。 对于所有受支持的 客户端扩展,客户端会将扩展标识符为键、扩展输入为值,加入 clientExtensions 有序字典。
同理,客户端扩展输出
作为字典返回,由 getClientExtensionResults()
产出,
以扩展标识符为键、客户端扩展输出为值。与 客户端扩展输入一样,客户端扩展输出 也可被 JSON 编码。
对于被忽略的扩展不得返回任何值。
需认证器处理的扩展必须定义使用 客户端扩展输入 派生出 CBOR 认证器扩展输入 的方法,以及如何利用 CBOR 认证器扩展输出 及 未签名扩展输出 生成 客户端扩展输出。
9.5. 认证器扩展处理
各受支持的 认证器扩展 的 CBOR 认证器扩展输入 包含于 authenticatorMakeCredential 和 authenticatorGetAssertion 操作的 extensions 参数内。参数为 CBOR 字典,键为 扩展标识符,值为该扩展的 认证器扩展输入。
扩展输出表现在 extensions 区域(认证器数据的一部分),其格式为 CBOR 字典,每键为 扩展标识符,值为 认证器扩展输出。
未签名扩展输出 独立于 认证器数据 返回,以同一扩展标识符为键的字典单独返回,只包含用到未签名输出的扩展。未签名输出适用于扩展需输出认证器数据签名(因无法对自身签名),或部分扩展输出不应传给 Relying Party 场景。
注意: 在 [FIDO-CTAP] 中,未签名扩展输出 作为顶层 unsignedExtensionOutputs 字段返回,包括
authenticatorMakeCredential 与 authenticatorGetAssertion
操作。
每个受支持扩展,均依据其 认证器扩展处理 规则,将 认证器扩展输入(以及其它所需输入)转换为 认证器扩展输出,如需还可产出 未签名扩展输出,被忽略的扩展不得有输出。
10. 已定义扩展
本节及其小节定义了应注册于 IANA“WebAuthn 扩展标识符”注册表 [IANA-WebAuthn-Registries](由 [RFC8809] 建立)的扩展,可供致力于广泛互操作性的用户代理实现。
10.1. 客户端扩展
本节定义仅为客户端扩展的扩展。
10.1.1. FIDO AppID扩展(appid)
本扩展允许已使用传统 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI] 注册凭据的 WebAuthn Relying Parties 请求 断言。FIDO API 使用一种称为 AppID 的 Relying Party 替代标识符 [FIDO-APPID],所有通过该 API 创建的凭据均限定在该标识范围。若无此扩展,须重新注册才能限定到 RP ID。
除设置 appid
输入外,使用本扩展还要求 Relying Party
进行一些额外处理,以允许用户使用已注册 U2F 凭据认证:
-
将所需 U2F 凭据列入
allowCredentials选项,作为get()方法参数:-
将
type成员设为public-key。 -
将
id成员设为相应 U2F 凭据的 key handle。注意,U2F key handle 常用 base64url 编码,但在id处须解码为二进制。
allowCredentials可同时含 WebAuthn credential ID 与 U2F key handle; 使用此扩展指定的appid并不妨碍用户用限定到 RP ID(参数rpId)的 WebAuthn 凭据。 -
本扩展不允许创建 FIDO 兼容的凭据,故 WebAuthn 创建的凭据不能与传统 FIDO JavaScript API 兼容。
注意:appid
应当设置为依赖方
之前在传统 FIDO API 中使用的 AppID。
这可能与将依赖方当前 WebAuthn 的RP ID转换为 AppID 格式的结果不同,
例如,之前使用的 AppID 可能是 "https://accounts.example.com",
而当前使用的RP ID 可能是 "example.com"。
- 扩展标识符
-
appid - 可用操作
- 客户端扩展输入
-
一个 DOMString,指定 FIDO AppID。
partial dictionary AuthenticationExtensionsClientInputs {DOMString ; };appid - 客户端扩展处理
-
-
令 facetId 为调用者 origin 交由 FIDO 算法确定应用 FacetID 的结果。
-
将 appId 设为扩展输入值。
-
将 facetId 与 appId 交由 FIDO 算法判断 FacetID 是否获授权使用 AppID,如拒绝则抛出 "
SecurityError"DOMException。 -
构建 allowCredentialDescriptorList 时, 若 U2F 认证器反馈凭据不适用(如返回
SW_WRONG_DATA),客户端须用 appId 的 SHA-256 哈希作为 U2F application parameter 重试。若返回适用凭据,必须将该凭据纳入 allowCredentialDescriptorList,并用 appId 替换 authenticatorGetAssertion 的rpId参数。 -
置 output 为布尔值
false。 -
创建 assertionCreationData 时, 若断言由 U2F 认证器在 application parameter 为 appId 的 SHA-256 哈希时生成,则将 output 设为
true。
-
注意: 实际上,多实现并未完整实现 “判断 FacetID 是否获授权使用 AppID” 算法的第四步及之后流程,仅在主机名对比时,三步处放宽为接受同一 网站 的主机。
- 客户端扩展输出
-
返回 output 的值。若为 true,表示已用 AppID,Relying Party 校验断言时须以 AppID 哈希做
rpIdHash,而不是 RP ID 哈希。partial dictionary AuthenticationExtensionsClientOutputs {boolean ; };appid - 认证器扩展输入
-
无。
- 认证器扩展处理
-
无。
- 认证器扩展输出
-
无。
10.1.2. FIDO AppID 排除扩展(appidExclude)
该注册扩展允许WebAuthn Relying Party 排除包含指定通过传统 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI] 创建凭据的认证器。
在从 FIDO U2F JavaScript API 迁移过程中,Relying Party 可能有一部分用户已经注册了传统凭据。appid 扩展可平滑迁移登录流程,但迁移注册流程时,excludeCredentials 字段将无法有效排除含有传统凭据的认证器,因为它的内容被视为 WebAuthn 凭据。此扩展指示客户端平台将excludeCredentials内容同时视为 WebAuthn 和传统 FIDO 凭据。注意 U2F key handle 通常使用 base64url 编码,但用作 excludeCredentials 时须解码成二进制。
- 扩展标识符
-
appidExclude - 适用操作
- 客户端扩展输入
-
一个 DOMString,指定 FIDO AppID。
partial dictionary AuthenticationExtensionsClientInputs {DOMString ; };appidExclude - 客户端扩展处理
-
当创建新凭据时:
-
在 确定 RP ID 后,执行如下步骤:
-
令 facetId 为调用方 origin 传递给 FIDO 算法的结果,用于确定应用 FacetID。
-
令 appId 为扩展输入
appidExclude的值。 -
将 facetId 和 appId 传递给 FIDO 算法判断 FacetID 是否被授权用于该 AppID。若该算法拒绝 appId,则 返回 "
SecurityError"DOMException并终止创建新凭据算法及后续步骤。注意: 实际上,多数实现未实现该算法的第四步及其后流程,第三步主机比较实际放宽为接受同一网站的主机。
-
否则,继续正常流程。
-
-
在 调用 authenticatorMakeCredential 之前,执行如下步骤:
-
如 authenticator 支持 U2F 协议 [FIDO-U2F-Message-Formats], 则对 excludeCredentialDescriptorList 中的每个凭据描述符 C:
-
通过向 authenticator 发送一个
U2F_AUTHENTICATE消息,其“五部分”如下,检测 C 是否由该 authenticator 使用 U2F 创建:- control byte
-
0x07(仅检测) - challenge parameter
-
32 字节随机数
- application parameter
-
appId 的 SHA-256 哈希
- key handle length
-
C.的字节长度id - key handle
-
C.的值, 即 credential id。id
-
如 authenticator 响应
message:error:test-of-user-presence-required(即成功),则停止该认证器的正常流程,并以平台相关方式提示该认证器不可用。例如,可通过 UI 呈现,或请求 用户同意,收到后视为认证器返回InvalidStateError。请求用户同意可通过再次发送U2F_AUTHENTICATE消息给 authenticator,但 control byte 设为0x03(强制用户在场并签名),且忽略响应。
-
-
继续正常处理。
-
-
- 客户端扩展输出
-
返回
true,用于告知Relying Party 扩展已被执行。partial dictionary AuthenticationExtensionsClientOutputs {boolean ; };appidExclude - 认证器扩展输入
-
无。
- 认证器扩展处理
-
无。
- 认证器扩展输出
-
无。
10.1.3. 凭据属性扩展(credProps)
该客户端注册扩展,允许在注册典礼创建公钥凭据源时,由客户端向请求的WebAuthn Relying Party报告已知的某些凭据属性。
目前仅定义了一种凭据属性:客户端可发现凭据属性。
- 扩展标识符
-
credProps - 适用操作
- 客户端扩展输入
-
布尔值
true,表示 Relying Party 请求该扩展。partial dictionary AuthenticationExtensionsClientInputs {boolean ; };credProps - 客户端扩展处理
-
将
rk设置为 调用authenticatorMakeCredential 操作时使用的 requireResidentKey 参数的值。 - 客户端扩展输出
-
设置
clientExtensionResults["为在调用authenticatorMakeCredential操作时使用的requireResidentKey参数的值。credProps"]["rk"]dictionary {CredentialPropertiesOutput boolean rk ; };partial dictionary AuthenticationExtensionsClientOutputs {CredentialPropertiesOutput ; };credProps rk, 类型为 布尔值-
该可选属性,抽象名称为 客户端可发现凭据属性 或 驻留密钥属性, 是一个布尔值,指示由注册典礼结果返回的
PublicKeyCredential是否为客户端可发现凭据。 若rk为true,则该凭据为可发现凭据。 若rk为false,则凭据为服务端凭据。 若rk缺省,则无法确定凭据是可发现凭据还是服务端凭据。注意:某些认证器即使未被客户端平台请求,也会创建可发现凭据。因此,客户端平台可能无法确信地设置
rk属性为false而被迫省略它。Relying Party 应假定,只要支持credProps扩展,客户端平台会尽力填充rk属性。因此如果缺少rk,则该凭据很可能是不可发现凭据。
- 认证器扩展输入
-
无。
- 认证器扩展处理
-
无。
- 认证器扩展输出
-
无。
10.1.4. 伪随机函数扩展(prf)
该客户端 注册扩展和认证扩展,允许Relying Party评估与某个凭据相关联的伪随机函数(PRF)输出。该扩展提供的 PRF,将任意长度的 BufferSource
映射为 32 字节 BufferSource。
举例来说,PRF 输出可用作对称密钥加密用户数据。离开凭据断言(assertion)的情境,这类加密数据无法访问。按照下方规定,在一次断言操作中对两个输入分别评估 PRF,可实现加密密钥周期轮换,方式为断言时选择新随机输入并用新输出重新加密。若输入不可预测,即使攻击者可以通过用户验证,且在有限时间内获得认证器,也无法获得加密密钥除非其知道正确的 PRF 输入。
此扩展基于 [FIDO-CTAP] 的 hmac-secret
扩展实现。它是一个独立的客户端扩展,因为
hmac-secret 要求输入输出加密并只能由 user agent 进行,并区分 WebAuthn 与底层平台其它用途。实现隔离通过将提供的 PRF
输入与上下文字符串哈希来实现,从而避免对任意输入评估 PRF。
hmac-secret 为每个凭据提供两套 PRF:一个用于请求用户验证的情形,一个用于其它所有情形。本扩展仅公开每个凭据 1 套 PRF,基于 hmac-secret
时,必须选用有用户验证时的
PRF。必要时可覆盖 UserVerificationRequirement。
注意:即使不支持 [FIDO-CTAP] 的 认证器,只要在 Relying Party 观察下行为一致也可实现本扩展。
- 扩展标识符
-
prf - 适用操作
- 客户端扩展输入
-
dictionary {AuthenticationExtensionsPRFValues required BufferSource ;first BufferSource ; };second dictionary {AuthenticationExtensionsPRFInputs AuthenticationExtensionsPRFValues eval ;record <DOMString ,AuthenticationExtensionsPRFValues >evalByCredential ; };partial dictionary AuthenticationExtensionsClientInputs {AuthenticationExtensionsPRFInputs ; };prf eval, 类型为 AuthenticationExtensionsPRFValues-
要评估 PRF 的一个或两个输入。不是所有认证器都在创建凭据时支持评估 PRF,输出可能会或不会给出,如无则需断言才能获得输出。
evalByCredential, 类型为 record<DOMString, AuthenticationExtensionsPRFValues>-
将base64url 编码的凭据ID映射到该凭据需评估的 PRF 输入。只在
allowCredentials非空的断言环节适用。
- 客户端扩展处理(注册场景)
-
-
如存在
evalByCredential,则返回DOMException,name 为“NotSupportedError”。 -
在认证器扩展输入中将
hmac-secret设为true。 -
如有
eval,且未来有 FIDO-CTAP 扩展允许创建时评估 PRF,可按如下配置hmac-secret输入: -
将
results设为解密出的 PRF 结果(如有)。
-
- 客户端扩展处理(认证场景)
-
-
如
evalByCredential非空但allowCredentials为空,返回DOMException,name 为“NotSupportedError”。 -
如
evalByCredential内有键为空字符串,或不是有效的 base64url 编码,或(解码后)与id不匹配任何allowCredentials元素,则返回DOMException,name 为“SyntaxError”。 -
将
prf扩展输出初始化为空字典。 -
令 ev 为 null,尝试找到适用的 PRF 输入:
-
如存在
evalByCredential且包含与返回的凭据ID base64url 编码匹配的 entry,则令 ev 为该 entry 的值。 -
如 ev 为空,且
eval存在,则 ev 赋值为其值。
-
-
如 ev 非空:
-
- 认证器扩展输入/处理/输出
-
本扩展与认证器通信时使用 [FIDO-CTAP] 的
hmac-secret扩展,因此不针对 Relying Party 指定任何直接认证器交互要求。 - 客户端扩展输出
-
dictionary {AuthenticationExtensionsPRFOutputs boolean enabled ;AuthenticationExtensionsPRFValues results ; };partial dictionary AuthenticationExtensionsClientOutputs {AuthenticationExtensionsPRFOutputs ; };prf enabled, 类型为 布尔值results, 类型为 AuthenticationExtensionsPRFValues-
对
eval或evalByCredential里给定输入的 PRF 评估结果。注册时可能没有输出,见eval的注释。某些场景下,例如 PRF 输出仅用于本地派生加密密钥且凭据通过网络传输到远程服务器时,应省略本
results输出,比如参见 § 7 WebAuthn Relying Party 操作。尤其注意,RegistrationResponseJSON与AuthenticationResponseJSON由导出时,如有,本结果也会被包含。PublicKeyCredential.toJSON()
10.1.5. 大对象(Large blob)存储扩展(largeBlob)
该客户端 注册扩展和认证扩展允许Relying Party存储与凭据关联的不透明数据。由于认证器只能存储少量数据,且多数Relying Party为可存储任意用户状态的在线服务,这一扩展只在特定场景有用。例如,Relying Party 可能期望签发证书而非运行集中式认证服务。
注意:Relying Party 可以假定写入受空间限制设备时不透明数据会被自动压缩,因此无需自己再压缩。
由于证书系统需要对凭据的公钥签名,而公钥只有在创建后才可获得,本扩展在注册上下文中不支持写入 blob。不过,若Relying Party打算后续使用认证扩展,则应在创建凭据时使用注册扩展。
考虑到证书大小相较于认证器典型存储能力较大,user agent 应根据实际情况提示并确认用户,以帮助用户合理分配有限资源并防止滥用。
注意: 为实现互操作,user agent 在使用 [FIDO-CTAP] 在认证器存储 large blob 时,需遵循该规范内关于存储大对象 per-credential blob的相关规定。
注意: 基于 [FIDO-CTAP] 作为跨平台协议的漫游认证器,仅对可发现凭据支持本
largeBlob 扩展,且如
未设为 authenticatorSelection.residentKeypreferred
或 required,
可能返回错误。但不使用 [FIDO-CTAP] 的认证器不必将该扩展限制于可发现凭据。
- 扩展标识符
-
largeBlob - 适用操作
- 客户端扩展输入
-
partial dictionary AuthenticationExtensionsClientInputs {AuthenticationExtensionsLargeBlobInputs ; };largeBlob enum {LargeBlobSupport ,"required" , };"preferred" dictionary {AuthenticationExtensionsLargeBlobInputs DOMString support ;boolean read ;BufferSource write ; };support, 类型为 DOMString-
可取
LargeBlobSupport枚举值之一的 DOMString。(见§ 2.1.1 枚举作为 DOMString)。仅在注册阶段有效。 read, 类型为 boolean-
布尔值,表示Relying Party希望读取与当前凭据关联的已写入 blob。仅在认证阶段有效。
write, 类型为 BufferSource-
Relying Party 希望存储到该凭据上的不透明字节串,仅在认证阶段有效。
- 客户端扩展处理(注册)
- 客户端扩展处理(认证)
-
-
如
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 dictionary {AuthenticationExtensionsLargeBlobOutputs boolean supported ;ArrayBuffer blob ;boolean written ; }; - 认证器扩展处理
-
本扩展指示 user agent 把 large blob 存储到认证器或从认证器读取,不要求 Relying Party 直接与认证器交互。
10.2. 认证器扩展
本节当前为空。
11. 用户代理自动化
为用户代理自动化和Web 应用测试,本文件定义了若干 [WebDriver] 扩展命令。
11.1. WebAuthn WebDriver 扩展能力
为了声明下文定义的扩展命令的可用性,定义了一个新的扩展能力。
当校验能力时,针对 "webauthn:virtualAuthenticators" 和
value 的扩展子步骤如下:
-
如果
value不是布尔值,则返回 WebDriver 错误, 错误码为 WebDriver error code invalid argument。 -
否则,将
deserialized设为value。
当匹配能力时,针对 "webauthn:virtualAuthenticators" 和
value 的扩展子步骤如下:
11.1.1. 认证器扩展能力
此外,为本规范中定义的每个认证器扩展(即定义了认证器扩展处理的扩展)都定义了扩展能力:
| 能力 | 关键字 | 值类型 | 描述 |
|---|---|---|---|
| 伪随机函数扩展支持 | "webauthn:extension:prf"
| boolean | 指示端节点的 WebAuthn WebDriver 实现是否支持 prf 扩展。 |
| 大对象存储扩展支持 | "webauthn:extension:largeBlob"
| boolean | 指示端节点的 WebAuthn WebDriver 实现是否支持largeBlob 扩展。 |
| credBlob 扩展支持 | "webauthn:extension:credBlob"
| boolean | 指示端节点的 WebAuthn WebDriver 实现是否支持 credBlob
扩展(见 [FIDO-CTAP])。
|
当校验能力时,针对 认证器扩展能力
key 和 value 的扩展子步骤如下:
-
如果
value不是布尔值,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。 -
否则,将
deserialized设为value。
当匹配能力时,针对 认证器扩展能力key 和 value
的扩展子步骤如下:
实现已定义认证器扩展的 User-Agent 应实现相应的认证器扩展能力。
11.2. 虚拟认证器
这些 WebDriver 扩展命令用于创建和交互虚拟认证器:也即认证器模型的软件实现。虚拟认证器存放于虚拟认证器数据库。 每个存储的虚拟认证器具备以下属性:
- authenticatorId
-
一个非空字符串,使用 [RFC3986] 附录A
unreserved产生式中的最多 48 个字符唯一标识虚拟认证器。 - protocol
-
该虚拟认证器所用协议,可取
"ctap1/u2f"、"ctap2"、"ctap2_1"之一 [FIDO-CTAP]。 - transport
-
模拟的
AuthenticatorTransport。若 transport 为internal,则模拟平台附属,否则为跨平台附属。 - hasResidentKey
-
若为
true,则该认证器支持客户端可发现凭据。 - hasUserVerification
-
若为
true,认证器支持用户验证。 - isUserConsenting
-
决定了所有用户同意 授权手势的结果,并由此决定此虚拟认证器上的用户在场测试的结果。若为
true,总是同意用户同意流程;若为false,则总是不通过。 - isUserVerified
-
决定在虚拟认证器上执行的用户验证结果。若为
true,总是验证通过;若为false,总是失败。注意:若 hasUserVerification 为
false,该属性无效。 - extensions
- defaultBackupEligibility
-
决定任何新建公钥凭据源的可备份性凭据属性默认值。 该值在该虚拟认证器执行authenticatorMakeCredential操作时,需反映在BE位(认证器数据的标志)。
- defaultBackupState
-
决定任何新建公钥凭据源的备份状态凭据属性默认值。 该值在虚拟认证器执行authenticatorMakeCredential操作时,需体现在BS位(认证器数据的标志)。
11.3. 添加虚拟认证器
添加虚拟认证器 WebDriver 扩展命令用于创建一个软件虚拟认证器。定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| POST | /session/{session id}/webauthn/authenticator
|
认证器配置 是一个 JSON 对象,以 parameters 传入远端步骤。其内容为如下 key - value 对:
| 关键字 | 值类型 | 有效值 | 默认值 |
|---|---|---|---|
| protocol | string | "ctap1/u2f", "ctap2", "ctap2_1"
| 无 |
| transport | string | AuthenticatorTransport
各值
| 无 |
| hasResidentKey | boolean | true, false
| false
|
| hasUserVerification | boolean | true, false
| false
|
| isUserConsenting | boolean | true, false
| true
|
| isUserVerified | boolean | true, false
| false
|
| extensions | string array | 包含扩展标识符的数组 | 空数组 |
| defaultBackupEligibility | boolean | true, false
| false
|
| defaultBackupState | boolean | true, false
| false
|
远端步骤如下:
-
如果 parameters 不是一个 JSON 对象,则返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
注意: parameters 就是认证器配置对象。
-
令 authenticator 为新建的虚拟认证器。
-
对 parameters 的每个可枚举自身属性:
-
令 key 为属性名。
-
令 value 为获取 parameters 上名为 key 的属性的结果。
-
如 key 在认证器配置中不存在,返回WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
如 value 非该 key 的有效值,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
设置 authenticator 的属性 key 为 value。
-
-
对认证器配置里定义了默认值的每个属性:
-
如
key非 authenticator 的属性,则设置该属性为默认值。
-
-
对认证器配置中的每个属性:
-
如
key非 authenticator 已定义属性,则返回WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
-
对 authenticator.extensions 内的每个 extension:
-
若 extension 并非端节点 WebAuthn WebDriver 实现支持的扩展标识符,则返回 WebDriver 错误,错误码为 WebDriver error code unsupported operation。
-
-
生成一个有效的唯一authenticatorId。
-
设置 authenticator 的
authenticatorId属性为 authenticatorId。 -
将 authenticator 存入虚拟认证器数据库。
-
以 authenticatorId 为数据,返回成功。
11.4. 移除虚拟认证器
移除虚拟认证器 WebDriver 扩展命令用于移除之前创建的虚拟认证器。 定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| DELETE | /session/{session id}/webauthn/authenticator/{authenticatorId}
|
远端步骤如下:
-
如果 authenticatorId 未匹配任何存储于虚拟认证器数据库中的实例,返回WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
返回成功。
11.5. 添加凭据
添加凭据 WebDriver 扩展命令将公钥凭据源注入到已有的虚拟认证器中,定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| POST | /session/{session id}/webauthn/authenticator/{authenticatorId}/credential
|
凭据参数 是一个 JSON 对象,作为 parameters 传递给远端步骤。包含以下 key - value 对:
| 关键字 | 描述 | 值类型 |
|---|---|---|
| credentialId | 凭据 ID,使用Base64url 编码。 | string |
| isResidentCredential | 若为 true,创建客户端可发现凭据;为 false
时创建服务端凭据。
| boolean |
| rpId | 凭据适用的Relying Party ID。 | string |
| privateKey | 非对称密钥包,包含每个凭据的单一私钥,格式参考 [RFC5958],Base64url 编码。 | string |
| userHandle | 关联该凭据的userHandle,Base64url 编码。可选属性。 | string |
| signCount | 签名计数器的初始值,关联该公钥凭据源。 | number |
| largeBlob | 关联该大型 blob,Base64url 编码。可选属性。 | string |
| backupEligibility | 该凭据的可备份性模拟属性。如果未设置,默认为 虚拟认证器的 defaultBackupEligibility。 执行authenticatorGetAssertion 时,模拟可备份性必须反映在BE 认证器数据的标志上。 | boolean |
| backupState | 该凭据的备份状态模拟属性。如果未设置,默认为虚拟认证器的 defaultBackupState。执行 authenticatorGetAssertion 时,需反映在 BS 认证器数据的标志上。 | boolean |
| userName | 该凭据对应user的name。未设置时默认为空字符串。
| string |
| userDisplayName | 该凭据对应user的displayName。未设置时默认为空字符串。
| string |
远端步骤如下:
-
如果 parameters 不是一个 JSON 对象,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
注意: parameters 是凭据参数对象。
-
将 parameters 的 credentialId 属性通过Base64url 解码,设为 credentialId。
-
如 credentialId 解析失败,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
取 parameters 的 isResidentCredential 属性赋值给 isResidentCredential。
-
如 isResidentCredential 未定义,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
取 parameters 的 rpId 属性赋值为 rpId。
-
如 rpId 非有效 RP ID,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
将 parameters 的 privateKey 属性通过 Base64url 解码,得到 privateKey。
-
如 privateKey 解码失败,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
如 privateKey 非有效编码的仅含单一 P-256 曲线 ECDSA 私钥的密钥包(见 [RFC5958]),返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
如果 parameters 的 userHandle 存在:
-
将 userHandle 设为 parameters 的 userHandle 属性 Base64url 解码。
-
如 userHandle 解码失败,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
-
否则:
-
如 isResidentCredential 为
true,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。 -
令 userHandle 为
null。
-
-
如 authenticatorId 未匹配到任何虚拟认证器,返回 WebDriver 错误,错误码 WebDriver error code invalid argument。
-
令 authenticator 为与 authenticatorId 匹配的虚拟认证器。
-
如 isResidentCredential 为
true且 authenticator 的 hasResidentKey 为false,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。 -
如果 authenticator 支持 largeBlob 扩展且 parameters 的 largeBlob 存在:
-
将 largeBlob 设为 parameters 的 largeBlob 属性 Base64url 解码后结果。
-
如 largeBlob 解码失败,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
-
否则:
-
令 largeBlob 为
null。
-
-
取 parameters 的 backupEligibility 属性为 backupEligibility。
-
如 backupEligibility 未定义,设为 authenticator 的 defaultBackupEligibility。
-
取 parameters 的 backupState 属性为 backupState。
-
如 backupState 未定义,设为 authenticator 的 defaultBackupState。
-
取 parameters 的 userName 属性。
-
如 userName 未定义,则设其值为空字符串。
-
取 parameters 的 userDisplayName 属性。
-
如 userDisplayName 未定义,则设其值为空字符串。
-
如 isResidentCredential 为
true,新建客户端可发现公钥凭据源;否则,新建服务端公钥凭据源。字段如下:- type
- id
-
credentialId
- privateKey
-
privateKey
- rpId
-
rpId
- userHandle
-
userHandle
- otherUI
-
由 userName 和 userDisplayName 构造。
-
为 credential 关联 签名计数器 counter,起始值为 parameters 的 signCount 或为
0(当 signCount 为null)。 -
如 largeBlob 非
null,将其作为该 credential 的 大型 blob -
将 credential 与 counter 存入 authenticator 的数据库。
-
返回成功。
11.6. 获取凭据
获取凭据
WebDriver 扩展命令会返回指定虚拟认证器中的每个公钥凭据源的凭据参数对象,无论该凭据是通过添加凭据还是 navigator.credentials.create()
存储的。
定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| GET | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials
|
远端步骤如下:
-
如 authenticatorId 未匹配任何存储于虚拟认证器数据库中的实例,返回WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
令 credentialsArray 为空数组。
-
对于由 authenticatorId 标识的认证器管理的每个公钥凭据源 credential,构造相应的凭据参数 对象,追加至 credentialsArray。
-
返回成功并包含 credentialsArray 数据。
11.7. 移除凭据
移除凭据 WebDriver 扩展命令将从虚拟认证器中删除一个公钥凭据源。定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| DELETE | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials/{credentialId}
|
远端步骤如下:
-
如果 authenticatorId 未匹配到任何存储在虚拟认证器数据库 虚拟认证器数据库中的对象,则返回WebDriver 错误,其WebDriver 错误码为invalid argument。
-
令 authenticator 为由 authenticatorId 标识的虚拟认证器。
-
如果 credentialId 未匹配到由 authenticator 管理的任何公钥凭证源,则返回WebDriver 错误, 其WebDriver 错误码为invalid argument。
-
移除由 authenticator 管理、由 credentialId 标识的公钥凭证源。
-
返回成功。
11.8. 移除全部凭据
移除全部凭据 WebDriver 扩展命令将从虚拟认证器中删除其存储的全部公钥凭据源。定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| DELETE | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials
|
远端步骤如下:
-
如 authenticatorId 未匹配任何存储于虚拟认证器数据库中的实例,返回WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
返回成功。
11.9. 设置用户已验证
设置用户已验证 扩展命令用于设置虚拟认证器上的 isUserVerified 属性。 定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| POST | /session/{session id}/webauthn/authenticator/{authenticatorId}/uv
|
远端步骤如下:
-
如 parameters 非 JSON 对象,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
如 authenticatorId 未匹配任何虚拟认证器,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
如 isUserVerified 非 parameters 的已定义属性,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
令 authenticator 为由 authenticatorId 标识的虚拟认证器。
-
将 authenticator 的 isUserVerified 属性设为 parameters 的 isUserVerified 属性值。
-
返回成功。
11.10. 设置凭据属性
设置凭据属性 扩展命令允许设置虚拟认证器中公钥凭据源的backupEligibility和backupState凭据属性。定义如下:
| HTTP 方法 | URI 模板 |
|---|---|
| POST | /session/{session id}/webauthn/authenticator/{authenticatorId}/credentials/{credentialId}/props
|
设置凭据属性参数 是一个 JSON 对象,作为 parameters 传递给远端步骤,包含以下 key - value 对:
远端步骤如下:
-
如 parameters 非 JSON 对象,返回 WebDriver 错误,错误码为 WebDriver error code invalid argument。
注意: parameters 即为设置凭据属性参数对象。
-
如 authenticatorId 未匹配任何存储于虚拟认证器数据库中的实例,返回WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
令 credential 为由 credentialId 匹配的 authenticator 管理的公钥凭据源。
-
如 credential 为空,返回WebDriver 错误,错误码为 WebDriver error code invalid argument。
-
取 parameters 的 backupEligibility 属性值。
-
如 backupEligibility 被定义,则将该 可备份性凭据属性设置为该值。
注意:通常情况下,backupEligibility 属性对公钥凭据源是永久属性。用 设置凭据属性 命令可用于测试和调试目的变更。
-
取 parameters 的 backupState 属性值。
-
返回成功。
12. IANA 考虑事项
12.1. WebAuthn 声明语句格式标识符注册更新
本节对 IANA "WebAuthn Attestation Statement Format Identifiers" 注册表 [IANA-WebAuthn-Registries] 中,§ 8 定义的声明语句格式中列出的格式进行了更新,前述注册表由 [RFC8809] 建立,初始注册源于 [WebAuthn-1],现指定引用为本规范。
-
WebAuthn 声明语句格式标识符: packed
-
描述: "packed" 声明语句格式为 WebAuthn 优化,是一种紧凑但可扩展的编码方式。适合资源受限(如安全元件)的认证器实现。
-
WebAuthn 声明语句格式标识符: tpm
-
描述: TPM 声明语句格式返回的结构与 packed 格式相同,但 rawData 和 signature 字段的计算方式不同。
-
规范文档: 本规范 § 8.3 TPM Attestation Statement Format
-
WebAuthn 声明语句格式标识符: android-key
-
描述: 版本 "N" 及以上的平台认证器可提供此专有的 "硬件声明" 语句。
-
WebAuthn 声明语句格式标识符: android-safetynet
-
描述: 基于安卓的平台认证器可基于 Android SafetyNet API 产生声明语句。
-
规范文档: 本规范 § 8.5 Android SafetyNet Attestation Statement Format
-
WebAuthn 声明语句格式标识符: fido-u2f
-
描述: 用于 FIDO U2F 认证器
12.2. WebAuthn 声明语句格式标识符注册
本节将 § 8 定义的声明语句格式中新定义的格式注册到由 [RFC8809] 建立的 IANA "WebAuthn Attestation Statement Format Identifiers" 注册表中。
-
WebAuthn 声明语句格式标识符: apple
-
描述: 用于 Apple 设备的平台认证器
-
规范文档: 本规范 § 8.8 Apple 匿名声明语句格式
-
WebAuthn 声明语句格式标识符: none
-
描述: 当WebAuthn Relying Party表示不需要收到声明信息时,用于替换认证器提供的声明语句。
-
规范文档: 本规范 § 8.7 None Attestation Statement Format
12.3. WebAuthn 扩展标识符注册更新
本节对 IANA "WebAuthn Extension Identifiers" 注册表 [IANA-WebAuthn-Registries] 中,§ 10 已定义扩展部分中列出的扩展标识符值进行了更新,前述注册表由 [RFC8809] 建立,初始注册源于 [WebAuthn-1],现指定引用为本规范。
-
WebAuthn 扩展标识符: appid
-
描述: 此认证扩展允许曾用传统 FIDO JS API 注册凭据的WebAuthn Relying Party请求断言。
-
规范文档: 本规范 § 10.1.1 FIDO AppID 扩展(appid)
12.4. WebAuthn 扩展标识符注册
本节将 § 10 已定义扩展中新增的扩展标识符注册到由 [RFC8809] 建立的 IANA "WebAuthn Extension Identifiers" 注册表。
-
WebAuthn 扩展标识符: appidExclude
-
描述: 该注册扩展允许WebAuthn Relying Party 排除含有通过传统 FIDO U2F JavaScript API [FIDOU2FJavaScriptAPI] 创建凭据的认证器。
-
规范文档: 本规范 § 10.1.2 FIDO AppID 排除扩展(appidExclude)
-
WebAuthn 扩展标识符: credProps
-
描述: 此客户端注册扩展可向回调的WebAuthn Relying Party的Web 应用上报新创建凭据属性(由客户端决定)。
-
规范文档: 本规范 § 10.1.3 凭据属性扩展(credProps)
-
WebAuthn 扩展标识符: largeBlob
-
描述: 此客户端 注册扩展和认证扩展允许Relying Party 存储与凭据关联的不透明数据。
-
规范文档: 本规范 § 10.1.5 大对象(largeBlob)存储扩展
13. 安全考虑
本规范定义了一个Web API以及一个密码学对等实体认证协议。 Web Authentication API允许 Web 开发者(即“作者”)在其注册 和认证流程中使用 Web Authentication 协议。 构成 Web Authentication 协议端点的实体是由用户控制的WebAuthn 认证器以及承载Relying Party的Web 应用的计算环境。 在该模型中,用户代理连同WebAuthn Client构成了认证器与Relying Party之间的中介。 另外,认证器可以向Relying Parties就其来源进行attest。
当前,本规范并未包含详尽的安全考量。但[FIDOSecRef] 文档提供了适用于本规范的总体安全分析。此外,[FIDOAuthnrSecReqs] 文档套件就认证器的安全特性提供了有用的信息。
下面的小节包含当前 Web Authentication 特有的安全考虑。它们按受众分组;一般性安全考虑作为本节的直接子节,而专门针对认证器、客户端和Relying Party实现者的安全考虑被分别归入各自的小节。
13.1. Credential ID 未签名
随同credential ID 一起返回的authentication assertion并未被签名。 这并不构成问题,因为如果某个authenticator返回了错误的credential ID, 或者攻击者截获并篡改了credential ID,则唯一会发生的情况是WebAuthn Relying Party无法查到用于验证返回的签名authenticator data(即assertion)的正确credential public key,从而导致交互以错误结束。
13.2. 客户端与认证器的物理接近性
在 WebAuthn 的认证器模型中,通常假定漫游认证器在物理上与客户端彼此靠近并直接通信。 这种安排具有一些重要优势。
客户端与认证器之间的物理接近性是something you have 认证因子的关键优势之一。 例如,如果一个漫游认证器仅能通过 USB 或 Bluetooth 通信,则这些传输的有限范围保证了任何恶意行为者必须在该范围内才能与认证器交互。 对于可以远程调用的authenticator,情况则不一定如此 —— 即使认证器验证了用户在场, 用户也可能被诱导批准远程发起的恶意请求。
客户端与认证器之间的直接通信使得客户端能够强制执行scope限制来约束凭据的使用。 相反,如果客户端与认证器之间的通信由第三方中介,则客户端必须信任该第三方来强制实施 scope 限制并控制对认证器的访问。 如果未能做到这两点,可能导致恶意的Relying Party接收到针对其它Relying Parties有效的authentication assertions, 或导致恶意用户获得针对其他用户的authentication assertions。
如果设计的解决方案不要求authenticator与client在物理上接近, 或客户端与认证器并不直接通信,设计者应当考虑这如何影响对scope限制的强制执行以及认证器作为something you have 认证因子的强度。
13.3. 针对认证器的安全考虑
13.3.1. Attestation 证书层次
建议采用三层的 attestation 证书层次(即 Attestation Root、Attestation Issuing CA、Attestation Certificate)。同时建议针对每个WebAuthn Authenticator 设备系列(即型号)使用单独的发行 CA,以便于将某个认证器型号特定版本的问题隔离处理。
如果 attestation 根证书并非专用于单一的WebAuthn Authenticator设备系列(即 AAGUID), 则建议在 attestation 证书本身中包含 AAGUID,以便可以将其与authenticator data进行比对验证。
13.3.2. Attestation 证书及其 CA 被攻破
当用于签发 attestation 证书的中间 CA 或根 CA 被攻破时,虽然WebAuthn Authenticator的attestation key pairs本身仍然安全,但它们的证书将不再可信。已记录其attestation public keys的WebAuthn Authenticator制造商可以从新的中间 CA 或新的根 CA 为这些密钥签发新的attestation certificates。如果根 CA 发生变化,WebAuthn Relying Parties必须相应地更新其受信任的根证书。
如果某个WebAuthn Authenticator的attestation certificate的私钥被泄露,则该 attestation 证书必须由签发 CA 吊销。若泄露源自固件缺陷,认证器制造商可能需要发布固件更新并向已出厂的WebAuthn Authenticators注入新的attestation private keys和certificates。(该过程超出本规范范围。)如果认证器制造商不具备此能力,则受影响的WebAuthn Authenticators的后续 attestation statements 可能无法被Relying Parties信任。
另见在 § 13.4.5 已吊销的 attestation 证书 中针对 Relying Parties 的相关安全考虑。
13.4. 针对Relying Parties的安全考虑
13.4.1. WebAuthn 对 Relying Parties 的安全收益
本规范为WebAuthn Relying Parties提供的主要好处包括:
-
可以使用广泛兼容且易用的多因素认证来保护用户和账户。
-
Relying Party无需向用户分发认证器硬件。相反,每个用户可以独立获取符合规范的authenticator并将同一认证器用于任意数量的Relying Parties。 Relying Party可以通过检查从认证器返回的attestation statements来可选地强制认证器的安全属性要求。
-
Authentication ceremonies 对中间人攻击具有抗性。关于registration ceremonies,见下文§ 13.4.4 Attestation Limitations。
-
Relying Party可以自动支持多种类型的用户验证(例如 PIN、生物识别以及未来的方法),几乎无需或只需很少修改代码,并允许每个用户通过其选择的authenticator来决定其偏好使用哪种方式。
-
Relying Party无需存储额外的秘密即可获得上述好处。
如在合规性节中所述,Relying Party必须按照§ 7 WebAuthn Relying Party Operations中所述的行为来获得所有上述安全收益。然而,一个在此略有偏离的显著用例在下文§ 13.4.4 Attestation Limitations中描述。
13.4.2. 嵌入式使用的可见性考虑
在嵌入式环境中简单使用 WebAuthn,例如在 § 5.10 在 iframe 元素中使用 Web 身份验证中描述的
iframe
内,
可能会让用户容易受到 UI 重绘(也称为 "点击劫持")攻击。这是指攻击者将自己的界面覆盖在依赖方期望显示的界面之上,诱使用户在依赖方界面执行非本意的操作。例如,通过这些技术,攻击者可能诱使用户购买商品、转账等。
即使 WebAuthn 专属界面通常由客户端平台处理,不易受到UI 重绘攻击,但对于在嵌入内容中使用 WebAuthn 的依赖方来说,确保自己的界面真正呈现在用户面前依然非常重要。近期出现的一种做法是监听实验性 Intersection Observer v2 的
isVisible 属性。例如,依赖方在嵌入式环境下运行的脚本可以在检测到 isVisible 等于 false
时,主动以弹窗方式打开自身内容,从而规避其内容被遮挡的问题。
13.4.3. 密码学挑战
作为一种密码学协议,Web Authentication 依赖于随机化的挑战以避免重放攻击。因此,PublicKeyCredentialCreationOptions.challenge
和 PublicKeyCredentialRequestOptions.challenge
的值必须由在其信任环境中(例如在服务器端)生成的Relying
Parties随机生成,且客户端响应中返回的challenge值必须与生成的值匹配。建议以不依赖客户端行为的方式进行,例如
Relying Party 应将挑战暂时存储直到操作完成。容忍不匹配将破坏协议的安全性。
挑战的有效期应与推荐的 WebAuthn 仪式超时范围和默认值的上限相近。
为防止重放攻击,挑战必须包含足够的熵以使其无法被猜测。因此,挑战建议至少为 16 字节长度。
13.4.4. Attestation 的局限性
本节非规范性。
在注册新凭据时,若存在,attestation statement 可能使WebAuthn Relying Party能够推断关于某些authenticator属性的保证,例如认证器模型或其如何存储和保护credential private keys。 然而重要的是要注意,仅凭attestation statement本身并不能让Relying Party验证某个attestation object是否由用户预期的认证器生成,而非由中间人攻击者生成。 例如,攻击者可以利用注入到Relying Party脚本中的恶意代码。 因此,Relying Party必须依赖其他手段,例如 TLS 及相关技术,来保护attestation object不受中间人攻击。
在假设registration ceremony已安全完成且认证器对credential private key保密的前提下,随后使用该public key credential进行的authentication ceremonies对中间人攻击具有抗性。
上述讨论适用于所有attestation
types。在任何情况下,中间人攻击者都可能替换PublicKeyCredential对象,包括其attestation
statement和要注册的credential public key,并随后篡改为同一攻击者所控制且通过同一攻击者的途径传递的未来authentication assertions。
这种攻击可能会被检测到;因为Relying Party在注册时登记了攻击者的credential public key而不是用户的密钥,攻击者必须在后续所有针对该Relying Party的认证流程中持续篡改:未被篡改的流程将失败,从而可能揭露该攻击。
除Self Attestation和None以外的attestation types可以增加此类攻击的难度,因为Relying Parties可能向用户显示认证器信息(例如型号标识),攻击者因此可能需要使用与用户相同型号的真实authenticator,否则用户可能注意到 Relying Party 报告的认证器型号与其预期不同。
注意: 上述所有变体的中间人攻击相较于对传统密码认证的中间人攻击更难被攻击者实施。
13.4.5. 被吊销的 Attestation 证书
如果在验证attestation certificate时因中间 attestation CA 证书被吊销而失败,且Relying Party的策略要求在这些情形下拒绝注册/认证请求,则建议该Relying Party同时取消注册(或将信任级别标记为等同于“self attestation”)在 CA 被攻破日期之后使用链上至相同中间 CA 的 attestation 证书注册的public key credentials。因此建议Relying Parties在注册期间记住中间 attestation CA 证书,以便在此类证书被吊销后取消注册相关的public key credentials。
另见在 § 13.3.2 Attestation Certificate and Attestation Certificate CA Compromise 中针对authenticators的相关安全考虑。
13.4.6. 凭据丢失与密钥可迁移性
本规范并未定义备份credential private keys或在authenticators之间共享它们的协议。 通常预期credential private key永远不会离开创建它的authenticator。 因此,丢失一个authenticator通常意味着丢失与该认证器绑定的所有credentials,这可能会在用户仅向某个Relying Party注册了单个凭据时将其锁定出账户。 Web Authentication API 提供的替代方案不是备份或共享私钥,而是在同一用户下注册多个credentials。例如,用户可以在常用的客户端设备上注册平台凭据,并为备份或在新设备上使用注册一个或多个漫游凭据。
Relying Parties应允许并鼓励用户向同一用户账户注册多个credentials。
Relying
Parties应使用
和
excludeCredentials
选项来确保这些不同的credentials绑定到不同的authenticators。
user.id
13.4.7. 未受保护账户检测
本节非规范性。
此安全考虑适用于在认证流程的第一步使用非空 allowCredentials
参数的Relying Parties。
例如,当使用基于服务端凭据的认证作为第一认证步骤时。
在这种情况下,allowCredentials
参数可能泄露哪些用户账户已注册 WebAuthn
凭据、哪些未注册的信息,这可能表明账户保护的强度差别。
例如,假设攻击者可以仅提供用户名来发起认证流程,如果某些用户账户返回非空的allowCredentials而其他用户返回失败或需要密码挑战,
攻击者即可推断后者账户很可能未要求 WebAuthn assertion,从而将攻击聚焦于这些可能更弱的账户。
该问题与§ 14.6.2 用户名枚举和§ 14.6.3 通过 credential IDs 导致的隐私泄露中描述的问题相似,可用类似方法缓解。
13.4.8. 代码注入攻击
任何在某个来源、属于作用域内的依赖方的公钥凭证上的恶意代码,都可能导致 WebAuthn 所能提供的任何安全保障全部失效。WebAuthn 客户端只会在安全上下文中暴露 WebAuthn API, 这虽然能缓解最基础的攻击,但依赖方还应结合其他预防措施。
代码注入可能通过多种方式发生; 本节旨在指出一些可能的场景并提出相应的缓解措施, 但并非详尽列举。
-
恶意代码可能由依赖方包含的第三方脚本注入,无论是出于故意还是由于第三方存在安全漏洞。
-
根据凭证作用域规则,恶意代码可能被托管在RP ID的子域名上。 例如,由用户上传的代码被托管在
usercontent.example.org,可以操作任何凭证,只要这些凭证的作用域属于RP IDexample.org。 如果依赖方在验证断言时允许某个子域名origin, 恶意用户就可以利用这一点发起中间人攻击以获得有效的认证断言并冒充受害者身份。因此,依赖方默认情况下不应允许在验证断言时传入子域名
origin。 如果依赖方确实需要允许子域名origin, 那么依赖方不得在其 作用域内的任何被允许的 来源的子域名上提供不受信任的代码,这些作用域属于其公钥凭证。
13.4.9. 验证凭据的 origin
在注册凭据和在验证断言时,
Relying
Party必须验证客户端数据(client data)中的origin成员。
Relying Party不得接受意外的origin值,
因为这样可能允许恶意网站获取有效的credentials。
尽管 WebAuthn 凭据的scope防止其在注册时指定的 RP ID
之外的域上被使用,但 Relying Party 对 origin 的验证仍作为对可能出现的认证器未能正确执行凭据 scope 强制的额外防护层。另见§ 13.4.8 代码注入攻击中关于潜在恶意子域的讨论。
验证可以通过精确的字符串匹配或 Relying Party 所需的任何其它方法执行。例如:
-
仅在
https://example.org提供 Web 应用的情形下,Relying Party 应要求origin严格等于https://example.org。这是最简单的情形,其中
origin预期为以https://开头后接 RP ID 的字符串。 -
在少量域上提供 Web 应用的情形下,可能要求
origin严格等于允许原点列表中的某一项,例如["https://example.org", "https://login.example.org"]。 -
使用related origin requests的 Web 应用可能同样要求
origin严格等于允许原点列表中的某一项,例如["https://example.co.uk", "https://example.de", "https://myexamplerewards.com"]。该列表通常与 RP ID 的 well-known URI 中列出的原点相匹配。见 § 5.11 在相关原点间使用 Web Authentication。 -
在很多域上提供 Web 应用且这些域经常变化的情形下,Relying Party 可能结构性地解析
origin并要求 URL 的 scheme 为https且 authority 等于或属于 RP ID 的任一子域——例如允许example.org或其任意子域)。注意:允许 RP ID 的任意子域时的风险见 § 13.4.8 代码注入攻击。
-
具有配套本地应用的 Web 应用可能允许
origin为操作系统相关的本地应用标识符。例如,Relying Party 可能要求origin严格等于列表中的某一项,如["https://example.org", "example-os:appid:204ffa1a5af110ac483f131a1bef8a841a7adb0d8d135908bbd964ed05d2653b"]。
在验证客户端数据的topOrigin成员时也适用类似考虑。
当topOrigin存在时,Relying
Party 必须验证其值是否符合预期。该验证可以通过精确字符串匹配或 Relying Party 所需的任意方法执行。例如:
-
希望被少数域以跨域 iframe 嵌入的 Web 应用可能要求
topOrigin严格等于允许原点列表中的某一项,例如["https://example-partner1.org", "https://login.partner2-example.org"]。 -
希望被大量域以跨域 iframe 嵌入的 Web 应用可能允许
topOrigin的任意值,或使用动态程序来决定给定的topOrigin值是否对特定流程被允许。
14. 隐私考虑
[FIDO-Privacy-Principles] 中的隐私原则同样适用于本规范。
本节按受众划分;一般性隐私考虑作为本节的直接子节,而专门针对 authenticator、client 和 Relying Party 实现者的隐私考虑被分组到各自的小节中。
14.1. 防止去匿名化的措施
本节非规范性。
Web Authentication API 的许多设计要点是出于隐私考虑。本规范关注的主要问题是保护用户的个人身份,即识别某个人或者将不同身份关联为同一人。尽管 Web Authentication API 不使用也不提供任何形式的全局身份,下列可能被关联的标识符仍会被使用:
-
用户的 credential IDs 和 credential public keys。
这些由 WebAuthn Relying Party 注册,并由用户随后用于证明对相应 credential private key 的持有权。它们在与 authenticator 通信时也对 client 可见。
-
用户针对每个 Relying Party 的特定身份,例如用户名和 user handles。
这些身份显然被每个 Relying Party 用于在其系统中识别用户。它们在与 authenticator 通信时也对 client 可见。
-
用户的生物特征,例如指纹或面部识别数据 [ISOBiometricVocabulary]。
这可由 authenticator 选择性地用于执行 user verification。该数据不会被透露给 Relying Party,但在 platform authenticators 的情况下,视实现而定,生物数据可能对 client 可见。
-
用户使用的 authenticators 的型号,例如产品名称。
这会在注册期间提供给 Relying Party 的 attestation statement 中暴露,并且在与 authenticator 通信时对 client 可见。
-
用户的 authenticators 的身份,例如序列号。
这可能被 client 用于与 authenticator 建立通信,但不会向 Relying Party 暴露。
上述部分信息必须与 Relying Party 共享。下列小节描述了防止恶意 Relying Parties 利用这些信息识别用户个人身份所采取的措施。
14.2. 匿名、作用域限定、不可关联的 Public Key Credentials
本节非规范性。
虽然 Credential IDs 和 credential public keys 必须与 WebAuthn Relying Party 共享以启用强认证,但它们被设计为最小化可识别性且不在不同 Relying Parties 间共享。
-
Credential IDs 和 credential public keys 单独看并无意义,它们仅标识 credential key pairs,并不直接标识用户。
-
每个 public key credential 都严格地作用域于特定的 Relying Party,并且 client 确保其存在不会被其他 Relying Parties 发现。因此,恶意的 Relying Party 无法要求 client 透露用户的其他身份。
-
client 也确保在未获得 user consent 前,不会向 Relying Party 透露某个 public key credential 的存在。关于这点的详细内容见 § 14.5.1 Registration Ceremony Privacy 和 § 14.5.2 Authentication Ceremony Privacy。因此,即使用户已注册并可用,恶意 Relying Party 也无法在未告知用户的情况下静默地识别该用户。
-
Authenticators 确保不同 public key credentials 的 credential IDs 与 credential public keys 无法被关联为同一用户。这样一对恶意的 Relying Parties 就无法在没有额外信息(例如用户自行重用的用户名或电子邮件地址)的情况下在其系统间关联用户。
-
Authenticators 确保其 attestation certificates 不足以唯一识别某一台 authenticator 或一小群 authenticators。关于这点在 § 14.4.1 Attestation Privacy 中有进一步说明。因而一对恶意的 Relying Parties 也无法通过追踪单个 authenticators 在其系统间关联用户。
此外,client-side discoverable public key credential source 可选地包含由 Relying Party 指定的 user handle。该 credential 随后可用于同时标识并 authenticate 用户。这意味着一个注重隐私的 Relying Party 可以允许创建用户账户而无需传统用户名,从而进一步改善不同 Relying Parties 间的不可关联性。
14.3. Authenticator 本地的 生物识别
Biometric authenticators 在 authenticator 内部执行 biometric recognition —— 但对于 platform authenticators 来说,生物识别数据也可能(视实现而定)对 client 可见。生物识别数据不会被泄露给 WebAuthn Relying Party;它仅在本地用于执行授权创建或注册,或用于使用 public key credential 的 user verification。因此,恶意的 Relying Party 无法通过生物识别数据发现用户的个人身份,且当 Relying Party 出现安全漏洞时,也无法暴露生物识别数据以供攻击者在其他 Relying Parties 上伪造登录。
若 Relying Party 需要 biometric recognition,该识别由执行 user verification 的 biometric authenticator 在本地执行,然后通过在签名的 assertion 响应中设置 UV flag 来表明结果,而不是将生物识别数据本身泄露给 Relying Party。
14.4. 针对 authenticators 的隐私考虑
14.4.1. Attestation 隐私
Attestation certificates 和 attestation key pairs 可能被用来追踪用户或将同一用户的不同在线身份关联起来。可以通过多种方式减缓这种风险,包括:
-
WebAuthn Authenticator 制造商可以选择出厂时以批次方式分发 authenticators,使得一个批次内的 authenticators 共享相同的 attestation certificate(称为 Basic Attestation 或 batch attestation)。 这将通过群体匿名化来减少追踪,但会带来当某个 attestation certificate 的私钥被泄露时无法撤销特定证书的风险。认证器制造商应确保此类批次足够大以提供有意义的匿名化,同时在发生 attestation private key 泄露时,将受影响的用户数降到最低。
[UAFProtocol] 要求至少 100,000 台 authenticator 设备共享相同的 attestation certificate,以形成足够大的群体。该要求可作为合适批次规模的参考。
-
WebAuthn Authenticator 可能能够按 credential 动态生成不同的 attestation key pairs(并为其请求相应的 certificates),如本规范中所述的 Anonymization CA 方案。例如,认证器可随器件一并出厂时包含主 attestation private key(及其 certificate),并结合云端运营的 Anonymization CA,以动态生成按 credential 的 attestation key pairs 和 attestation certificates。
注意: 在本规范以外的若干地方,术语 "Privacy CA" 被用于表示此处称为 Anonymization CA 的概念。由于 Trusted Computing Group (TCG) 也曾使用 "Privacy CA" 来指代其所称的 Attestation CA(ACA),我们在此使用 Anonymization CA 一词以在本规范上下文中减少混淆。
14.4.2. 存储在认证器中的个人可识别信息的隐私
认证器可以向客户端提供本规范以外的附加信息,例如, 使客户端能够提供丰富的 UI,用户可以选择用于凭证进行认证仪式。如果认证器选择这么做,应避免在未成功执行用户验证时暴露任何个人可识别信息。如果认证器支持多个用户同时注册的用户验证,则应避免暴露当前已验证用户之外的人员信息。因此,不支持用户验证的认证器不应存储任何个人可识别信息。
在此讨论中,作为 id
成员传递的用户句柄(user handle)(PublicKeyCredentialUserEntity)不被视为个人可识别信息;详见§ 14.6.1 用户句柄内容。
这些建议旨在防止物理接触到认证器的攻击者,提取出该认证器中注册用户的个人可识别信息。
14.5. 客户端的隐私注意事项
14.5.1. 注册仪式的隐私
为了防止用户未同意被识别,实现
[[Create]](origin, options, sameOriginWithAncestors)
方法时需注意,不要泄露可让恶意WebAuthn 依赖方区分以下情况的信息,其中“排除”表示依赖方在 excludeCredentials
列出的至少一个凭证已绑定到认证器:
如果以上情况可区分,则会泄露信息,使恶意依赖方能通过探测可用的凭证来识别用户。例如,如果客户端一旦检测到被排除的认证器可用就立刻返回失败响应,就是一种信息泄露。在此情况下——尤其如果被排除的认证器为平台认证器——依赖方可以判断该仪式被取消发生在用户手动取消之前,从而推断出excludeCredentials参数中至少有一个凭证对该用户可用。
然而,如果用户已同意创建新凭证后才返回可区分的错误,则无需担心上述问题,因为此时用户已明确表示愿意共享即将泄露的信息。
14.5.2. 认证仪式的隐私
为防止用户被未同意的情况下识别,实现
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
方法时需注意,不要泄露可让恶意WebAuthn 依赖方区分以下情况的信息,其中“已命名”表示allowCredentials参数被依赖方列出:
如果上述情况可区分,则会泄露信息,使恶意依赖方可通过探测可用的凭证来识别用户。例如,如果客户端仅在发现包含已命名凭证的认证器后,才显示取消或继续认证仪式的操作提示和控件,也算一种信息泄露。在该情况下,如果依赖方了解客户端行为,就可以判断该仪式是用户手动取消的而非超时,从而推断allowCredentials参数中至少有一个凭证对该用户可用。
可通过始终为用户显示可取消认证仪式的控件予以缓解, 无论是否存在任何被命名的凭证。
14.5.3. 操作系统用户账户间的隐私
如果平台认证器集成于带有多用户操作系统的客户端设备中, 则平台认证器与客户端设备应协作保证,任何平台凭证的存在信息仅对创建该平台凭证的操作系统用户可见。
14.5.4. 客户端能力披露
getClientCapabilities
方法有助于WebAuthn
依赖方设计更有可能在客户端/用户处成功的注册与认证体验。
客户端支持或不支持某一 WebAuthn 能力,可能带来指纹跟踪风险。客户端实现可能需要根据客户端策略和/或用户同意来限制能力信息的披露。
14.6. 依赖方的隐私注意事项
14.6.1. 用户句柄内容
由于用户句柄在§ 14.4.2 存储在认证器中的个人可识别信息的隐私中不被视为个人可识别信息, 并且认证器可以在未执行用户验证的情况下暴露用户句柄, 因此依赖方不得在用户句柄中包含任何个人可识别信息,比如邮箱或用户名。如果散列的是个人可识别信息,也不允许使用(除非 hash 函数用仅对依赖方私有的盐做加盐散列),因为散列并不能防止针对容易猜测的输入值进行探测。建议用户句柄使用64字节随机值,并将其存储到用户账户中。
14.6.2. 用户名枚举
在发起注册或认证仪式时,WebAuthn 依赖方可能会泄露其已注册用户的敏感信息。例如,如果依赖方使用电子邮件地址作为用户名,攻击者尝试为 "alex.mueller@example.com" 发起认证 仪式且依赖方以失败响应,但随后为 "j.doe@example.com" 成功发起认证仪式,那么攻击者即可推断出 "j.doe@example.com" 已注册,而 "alex.mueller@example.com" 未注册。依赖方由此泄露了 "j.doe@example.com" 在此依赖方拥有用户账户的敏感信息。
以下是依赖方可采用以缓解或防止此类攻击造成信息泄漏的非规范性、非穷举性措施列表:
-
针对注册仪式:
-
针对认证仪式:
-
如果在发起认证仪式时,未能找到与所提供用户名匹配的用户账户,则应继续仪式,调用
navigator.credentials.get(),并传入以合理的虚构值填充的、语法有效的PublicKeyCredentialRequestOptions对象。这种做法同样可用于缓解通过
allowCredentials带来的信息泄露;参见§ 13.4.7 未受保护账户检测和§ 14.6.3 通过凭证ID的隐私泄漏。注意: 用户名可以通过依赖方特定方式“提供”:登录表单、会话cookie等。
注意: 若返回的虚构值与实际值存在明显差异,则聪明的攻击者可能识别出这些差异,进而检测实际账户的存在。明显差异的例子包括所有用户名输入返回的值始终一致,或者同一用户名多次尝试返回的值不同。因此,
allowCredentials成员可以用伪随机数填充,伪随机数如可以由用户名确定性导出等。 -
在验证来自认证器的
AuthenticatorAssertionResponse响应时,应使验证失败的原因在签名无效和帐号或凭证未注册之间无法区分。 -
通过多步骤认证仪式,如先输入用户名+密码或会话cookie,再作为后续步骤发起 WebAuthn 仪式。这样可以将用户名枚举问题从 WebAuthn 步骤转移到之前的认证步骤,从而可能更便于解决。
-
14.6.3. 通过 credential IDs 导致的隐私泄露
本节非规范性。
本隐私注意事项适用于支持非空 allowCredentials
参数作为首次认证步骤的依赖方,
例如使用服务器端凭证作为第一个认证步骤时。
在这种情况下,allowCredentials
参数有泄露个人可识别信息的风险,
因为它会将用户的凭证ID暴露给一个未认证的调用者。凭证ID旨在不能在不同依赖方间被关联,
但凭证ID的长度也许能透露是由哪类认证器所创建。
很可能用户会在多个依赖方使用相同的用户名和一组认证器,
因此allowCredentials
中凭证ID的数量及其长度
可能成为对用户进行去匿名化的全局相关标识。
知晓用户的凭证ID还使得攻击者即使只有片刻的物理接触用户的某个认证器,也能用来佐证其对用户身份的猜测。
为防止此类信息泄漏,依赖方可以例如:
-
在发起 WebAuthn 认证仪式以及暴露用户凭证ID之前, 先进行一个单独的认证步骤,如用户名+密码认证或会话Cookie认证。
-
使用客户端可发现凭证, 从而无需
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。
除非特别说明,示例包含无声明情况。
所有随机值均用HKDF-SHA-256 [RFC5869],以CDDL中标记为
'WebAuthn test vectors'
的基础输入密钥材料确定生成,
也可用h'576562417574686e207465737420766563746f7273'表示。
ECDSA签名使用确定性nonce [RFC6979]。
示例中的RSA密钥基于p≥1024的两个最小梅森素数2p - 1。
注意:
注: 实现CTAP2的认证器返回的声明对象使用的密钥与本规范不同。 这些示例反映了WebAuthn服务方所期望的声明对象格式, 所以CTAP2生成的声明对象 需要对key做转换才能与这些示例逐位相同。
16.1. 声明信任根证书
所有包含声明的示例都使用下方X.509
DER格式的声明信任根证书attestation_ca_cert,参见[RFC5280]:
attestation_ca_key = h'7809337f05740a96a78eedf9e9280499dcc8f2aa129616049ec1dccfe103eb2a' ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='Attestation CA', L=32) attestation_ca_serial_number = h'ed7f905d8bd0b414d1784913170a90b6' ; Derived by: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='Attestation CA', L=16) attestation_ca_cert = h'30820207308201ada003020102021100ed7f905d8bd0b414d1784913170a90b6300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a3062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d030107034200043269300e5ff7b699015f70cf80a8763bf705bc2e2af0c1b39cff718b7c35880ca30f319078d91b03389a006fdfc8a1dcd84edfa07d30aa13474a248a0dab5baaa3423040300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020106301d0603551d0e0416041445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d04030203480030450220483063b6bb08dcc83da33a02c11d2f42203176893554d138c614a36908724cc8022100f5ef2c912d4500b3e2f5b591d0622491e9f220dfd1f9734ec484bb7e90887663'
16.1.1. 无声明的 ES256 凭据
注册:
challenge = h'00c30fb78531c464d2b6771dab8d7b603c01162f2fa486bea70f283ae556e130' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='none.ES256', L=32) credential_private_key = h'6e68e7a58484a3264f66b77f5d6dc5bc36a47085b615c9727ab334e8c369c2ee' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='none.ES256', L=32) client_data_gen_flags = h'f9' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='none.ES256', L=1) ; extra_client_data 仅当 client_data_gen_flags 的第 0x01 位为 1 时包含 extra_client_data = h'06441e0e375c4c1ad70620302532c4e5' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='none.ES256', L=16) aaguid = h'8446ccb9ab1db374750b2367ff6f3a1f' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='none.ES256', L=16) credential_id = h'f91f391db4c9b2fde0ea70189cba3fb63f579ba6122b33ad94ff3ec330084be4' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='none.ES256', L=32) ; auth_data_UV_BE_BS 决定认证器数据标志中的 UV, BE 和 BS 位,但仅当 BE 被设置时才设置 BS auth_data_UV_BE_BS = h'ba' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='none.ES256', L=1) clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22414d4d507434557878475453746e63647134313759447742466938767049612d7077386f4f755657345441222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20426b5165446a646354427258426941774a544c4535513d3d227d' attestationObject = h'a363666d74646e6f6e656761747453746d74a068617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b559000000008446ccb9ab1db374750b2367ff6f3a1f0020f91f391db4c9b2fde0ea70189cba3fb63f579ba6122b33ad94ff3ec330084be4a5010203262001215820afefa16f97ca9b2d23eb86ccb64098d20db90856062eb249c33a9b672f26df61225820930a56b87a2fca66334b03458abf879717c12cc68ed73290af2e2664796b9220'
认证:
challenge = h'39c0e7521417ba54d43e8dc95174f423dee9bf3cd804ff6d65c857c9abf4d408' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='none.ES256', L=32) client_data_gen_flags = h'4a' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='none.ES256', L=1) ; extra_client_data 仅当 client_data_gen_flags 的第 0x01 位为 1 时包含 ; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,但仅当注册中设置了 BE 时,BS 才会被设置 auth_data_UV_BS = h'38' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='none.ES256', L=1) authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b51900000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a224f63446e55685158756c5455506f334a5558543049393770767a7a59425039745a63685879617630314167222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' signature = h'3046022100f50a4e2e4409249c4a853ba361282f09841df4dd4547a13a87780218deffcd380221008480ac0f0b93538174f575bf11a1dd5d78c6e486013f937295ea13653e331e87'
16.1.2. 自声明的 ES256 凭据
注册:
challenge = h'7869c2b772d4b58eba9378cf8f29e26cf935aa77df0da89fa99c0bdc0a76f7e5' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed-self.ES256', L=32) credential_private_key = h'b4bbfa5d68e1693b6ef5a19a0e60ef7ee2cbcac81f7fec7006ac3a21e0c5116a' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed-self.ES256', L=32) client_data_gen_flags = h'db' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed-self.ES256', L=1) ; extra_client_data 仅当 client_data_gen_flags 的第 0x01 位为 1 时包含 extra_client_data = h'53d8535ef284d944643276ffd3160756' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed-self.ES256', L=16) aaguid = h'df850e09db6afbdfab51697791506cfc' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed-self.ES256', L=16) credential_id = h'455ef34e2043a87db3d4afeb39bbcb6cc32df9347c789a865ecdca129cbef58c' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed-self.ES256', L=32) ; auth_data_UV_BE_BS 决定认证器数据标志中的 UV, BE 和 BS 位,但仅当 BE 被设置时才设置 BS auth_data_UV_BE_BS = h'fd' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed-self.ES256', L=1) clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a2265476e4374334c55745936366b336a506a796e6962506b31716e666644616966715a774c33417032392d55222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a205539685458764b453255526b4d6e625f3078594856673d3d227d' attestationObject = h'a363666d74667061636b65646761747453746d74a263616c67266373696758483046022100ae045923ded832b844cae4d5fc864277c0dc114ad713e271af0f0d371bd3ac540221009077a088ed51a673951ad3ba2673d5029bab65b64f4ea67b234321f86fcfac5d68617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55d00000000df850e09db6afbdfab51697791506cfc0020455ef34e2043a87db3d4afeb39bbcb6cc32df9347c789a865ecdca129cbef58ca5010203262001215820eb151c8176b225cc651559fecf07af450fd85802046656b34c18f6cf193843c5225820927b8aa427a2be1b8834d233a2d34f61f13bfd44119c325d5896e183fee484f2'
认证:
challenge = h'4478a10b1352348dd160c1353b0d469b5db19eb91c27f7dfa6fed39fe26af20b' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed-self.ES256', L=32) client_data_gen_flags = h'1f' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed-self.ES256', L=1) ; extra_client_data 仅当 client_data_gen_flags 的第 0x01 位为 1 时包含 extra_client_data = h'8136f9debcfa121496a265c6ce2982d5' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed-self.ES256', L=16) ; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,但仅当注册中设置了 BE 时,BS 才会被设置 auth_data_UV_BS = h'a1' ; 由以下方式生成: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed-self.ES256', L=1) authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50900000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a225248696843784e534e493352594d45314f7731476d3132786e726b634a5f6666707637546e2d4a71386773222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a206754623533727a36456853576f6d58477a696d4331513d3d227d' signature = h'3044022076691be76a8618976d9803c4cdc9b97d34a7af37e3bdc894a2bf54f040ffae850220448033a015296ffb09a762efd0d719a55346941e17e91ebf64c60d439d0b9744'
16.1.3. ES256 凭据,clientDataJSON 中 "crossOrigin" 为 true
注册:
challenge = h'3be5aacd03537142472340ab5969f240f1d87716e20b6807ac230655fa4b3b49' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='none.ES256.crossOrigin', L=32) 得出 credential_private_key = h'96c940e769bd9f1237c119f144fa61a4d56af0b3289685ae2bef7fb89620623d' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='none.ES256.crossOrigin', L=32) 得出 client_data_gen_flags = h'71' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='none.ES256.crossOrigin', L=1) 得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data extra_client_data = h'cd9aae12d0d1f435aaa56e6d0564c5ba' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='none.ES256.crossOrigin', L=16) 得出 aaguid = h'883f4f6014f19c09d87aa38123be48d0' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='none.ES256.crossOrigin', L=16) 得出 credential_id = h'6e1050c0d2ca2f07c755cb2c66a74c64fa43065c18f938354d9915db2bd5ce57' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='none.ES256.crossOrigin', L=32) 得出 ; auth_data_UV_BE_BS 决定认证器数据标志中的 UV、BE 和 BS 位,仅当 BE 为 1 时才设置 BS auth_data_UV_BE_BS = h'27' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='none.ES256.crossOrigin', L=1) 得出 clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a224f2d57717a514e5463554a484930437257576e7951504859647862694332674872434d475666704c4f306b222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a207a5a71754574445239445771705735744257544675673d3d227d' attestationObject = h'a363666d74646e6f6e656761747453746d74a068617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54500000000883f4f6014f19c09d87aa38123be48d000206e1050c0d2ca2f07c755cb2c66a74c64fa43065c18f938354d9915db2bd5ce57a501020326200121582022200a473f90b11078851550d03b4e44a2279f8c4eca27b3153dedfe03e4e97d225820cbd0be95e746ad6f5a8191be11756e4c0420e72f65b466d39bc56b8b123a9c6e'
认证:
challenge = h'876aa517ba83fdee65fcffdbca4c84eeae5d54f8041a1fc85c991e5bbb273137' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='none.ES256.crossOrigin', L=32) 得出 client_data_gen_flags = h'57' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='none.ES256.crossOrigin', L=1) 得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data extra_client_data = h'f76a5c4d50f401bcbeab876d9a3e9e7e' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='none.ES256.crossOrigin', L=16) 得出 ; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,仅当注册时 BE 为 1 时才设置 BS auth_data_UV_BS = h'0c' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='none.ES256.crossOrigin', L=1) 得出 authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50500000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a226832716c463771445f65356c5f505f62796b7945377135645650674547685f49584a6b655737736e4d5463222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a2039327063545644304162792d713464746d6a366566673d3d227d' signature = h'304402204396b14b216ed47920dc359e46aa0a1d4a912cf9d50f25a58ec236a11db4cf5e02204fdb59ff01656c4b0868e415436a464b0e30e94b02c719b995afaba9c917146b'
16.1.4. ES256 凭据,clientDataJSON 中含 "topOrigin"
注册:
challenge = h'4e1f4c6198699e33c14f192153f49d7e0e8e3577d5ac416c5f3adc92a41f27e5' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='none.ES256.topOrigin', L=32) 得出 credential_private_key = h'a2d6de40ab974b80d8c1ef78c6d4300097754f7e016afe7f8ea0ad9798b0d420' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='none.ES256.topOrigin', L=32) 得出 client_data_gen_flags = h'54' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='none.ES256.topOrigin', L=1) 得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data aaguid = h'97586fd09799a76401c200455099ef2a' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='none.ES256.topOrigin', L=16) 得出 credential_id = h'b8ad59b996047ab18e2ceb57206c362da57458793481f4a8ebf101c7ca7cc0f1' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='none.ES256.topOrigin', L=32) 得出 ; auth_data_UV_BE_BS 决定认证器数据标志中的 UV、BE 和 BS 位,仅当 BE 为 1 时才设置 BS auth_data_UV_BE_BS = h'a0' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='none.ES256.topOrigin', L=1) 得出 clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a225468394d595a68706e6a504254786b68555f53646667364f4e58665672454673587a72636b7151664a2d55222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22746f704f726967696e223a2268747470733a2f2f6578616d706c652e636f6d227d' attestationObject = h'a363666d74646e6f6e656761747453746d74a068617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b5410000000097586fd09799a76401c200455099ef2a0020b8ad59b996047ab18e2ceb57206c362da57458793481f4a8ebf101c7ca7cc0f1a5010203262001215820a1c47c1d82da4ebe82cd72207102b380670701993bc35398ae2e5726427fe01d22582086c1080d82987028c7f54ecb1b01185de243b359294a0ed210cd47480f0adc88'
认证:
challenge = h'd54a5c8ca4b62a8e3bb321e3b2bc73856f85a10150db2939ac195739eb1ea066' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='none.ES256.topOrigin', L=32) 得出 client_data_gen_flags = h'77' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='none.ES256.topOrigin', L=1) 得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data extra_client_data = h'52216824c5514070c0156162e2fc54a5' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='none.ES256.topOrigin', L=16) 得出 ; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,仅当注册时 BE 为 1 时才设置 BS auth_data_UV_BS = h'9f' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='none.ES256.topOrigin', L=1) 得出 authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50500000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22315570636a4b53324b6f34377379486a7372787a68572d466f51465132796b3572426c584f6573656f4759222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a747275652c22746f704f726967696e223a2268747470733a2f2f6578616d706c652e636f6d222c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a205569466f4a4d565251484441465746693476785570513d3d227d' signature = h'304402206a19613fa8cfacfc8027272aec5dae3555fea9f983d841581466678d71e6761a02207a9785ba22e48eb18525850357d9dc70795aaad2e6021159c4a4a183146eaa71'
16.1.5. ES256 凭据,超长的 credential ID
注册:
challenge = h'1113c7265ccf5e65124282fa1d7819a7a14cb8539aa4cdbec7487e5f35d8ec6c' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='none.ES256.long-credential-id', L=32) 得出 credential_private_key = h'6fd2149bb5f1597fe549b138794bde61893b2dc32ca316de65f04808dac211dc' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='none.ES256.long-credential-id', L=32) 得出 client_data_gen_flags = h'90' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='none.ES256.long-credential-id', L=1) 得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data aaguid = h'8f3360c2cd1b0ac14ffe0795c5d2638e' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='none.ES256.long-credential-id', L=16) 得出 credential_id = h'3a761a4e1674ad6c4305869435c0eee9c286172c229bb91b48b4ada140c0863417031305cce5b4a27a88d7fe728a5f5a627de771b4b40e77f187980c124f9fe832d7136010436a056cce716680587d23187cf1fc2c62ae86fc3e508ee9617ffc74fbc10488ec16ec5e9096328669a898709b655e549738c666c1ae6281dc3b5f733c251d3eefb76ee70a3805ca91bcc18e49c8dc7f63ebcb486ba8c3d6ab52b88ff72c6a5bb47c32f3ee8683a3ddc8abf60870448ec8a21b5bdcb183c7dead870255575a6df96eb1b6a2a1019780cba9e4887b17ff1164bbbcc10eb0d86ed75984cd3fa3419103024507dfd9ce8f92c56af7914cb0bb50b87ba82a312bb7dcd93028dbdcd6adb266979667158335171e3682d37755701edbf9d872846a291d49e57ef09da1ec637f5052ed2aa7407f7e61827468e94b461844f4c67be5fa9c6055a566f8fdfc29d4bf78a9ff275f552cc68ba543fa3962eea36fd1ea8453764577d021d0a181efc1f6100ab2e4110039e21ee16970bda7432b6134492155afc126295b3a2eccd12c66a68e340969e995e3e8c9c476e395cfc21203414110779474f1c9797406637dbe414f132519d3bf0ce4f01734ef0e1a12c3ad604ff15d766b1624db6a5a7ccbff7bc35c9908df94aba277e0af48f04ff3d16381c47e5a37ed3988a67a3b1ecaa926336b33391fff04128f869991c9fabd905b6fe3ceef5f8b630ec1c5d2636d5b1961ad5ca5004170f6f5e482792aad989b0287fe91e5c479403397152f1fa56aa79b156eb47e6c8ea3eb175c34cfb38ad8e772874639b1023d4d01395c94e55831671cc022aa6fa1e02a02c2e4abc776f6960e51f83b71a8c0f207b6a347573977812c9aa5480b0011aa739bd4b76c18c000cc4757cceccb920f007c40c00e37e5ab21476cd9f6054a8fffb55a108f5c706e2cea2049d81fd321ff47d2a5761b0800955ab1d4f4889f55a84e2601c684f17a4ade7453ea49591d0b59c8d9a765052f62219cf6ef4a5dd9539f0617d6ebbebce7c000455475d18449e25c49ef9a1e3efe18c09082ebe2058d7c347defaa92f0664553b805c7d76bbfce5f330aca220ac90a789380fc479ea0d8793205813cca590a912f699ad52f991a1bc0a503c3ec4b2a696719e3c26591a87127f7305cc7e72f4c8e39355ebb06a5b1042990f38710ee7aa612ee4374bb82e878585a70a96c2a6b47f101a4ff154be4fd76a3167577a5cc54d9167c154c69ac35485e44cc898b719e1be3cc9c0fb5624b8f8a0dae10947a41bf848b6c1bb33d1006ec077d7e286e3f2a7b4843716390119449fe2721e81a5ed2333d331c7120765da58fadae73c19d9a8c4509cf8ac1e9d98b799a5274509069739b5823f3fb496663820033426988eefca53e580e0f9e0dfe0992fc2e53a97e053639f98577058f995bdbd41cefdb' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='none.ES256.long-credential-id', L=1023) 得出 ; auth_data_UV_BE_BS 决定认证器数据标志中的 UV、BE 和 BS 位,仅当 BE 为 1 时才设置 BS auth_data_UV_BE_BS = h'69' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='none.ES256.long-credential-id', L=1) 得出 clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22455250484a6c7a50586d5553516f4c364858675a7036464d75464f61704d322d7830682d587a5859374777222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' attestationObject = h'a363666d74646e6f6e656761747453746d74a0686175746844617461590483bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b549000000008f3360c2cd1b0ac14ffe0795c5d2638e03ff3a761a4e1674ad6c4305869435c0eee9c286172c229bb91b48b4ada140c0863417031305cce5b4a27a88d7fe728a5f5a627de771b4b40e77f187980c124f9fe832d7136010436a056cce716680587d23187cf1fc2c62ae86fc3e508ee9617ffc74fbc10488ec16ec5e9096328669a898709b655e549738c666c1ae6281dc3b5f733c251d3eefb76ee70a3805ca91bcc18e49c8dc7f63ebcb486ba8c3d6ab52b88ff72c6a5bb47c32f3ee8683a3ddc8abf60870448ec8a21b5bdcb183c7dead870255575a6df96eb1b6a2a1019780cba9e4887b17ff1164bbbcc10eb0d86ed75984cd3fa3419103024507dfd9ce8f92c56af7914cb0bb50b87ba82a312bb7dcd93028dbdcd6adb266979667158335171e3682d37755701edbf9d872846a291d49e57ef09da1ec637f5052ed2aa7407f7e61827468e94b461844f4c67be5fa9c6055a566f8fdfc29d4bf78a9ff275f552cc68ba543fa3962eea36fd1ea8453764577d021d0a181efc1f6100ab2e4110039e21ee16970bda7432b6134492155afc126295b3a2eccd12c66a68e340969e995e3e8c9c476e395cfc21203414110779474f1c9797406637dbe414f132519d3bf0ce4f01734ef0e1a12c3ad604ff15d766b1624db6a5a7ccbff7bc35c9908df94aba277e0af48f04ff3d16381c47e5a37ed3988a67a3b1ecaa926336b33391fff04128f869991c9fabd905b6fe3ceef5f8b630ec1c5d2636d5b1961ad5ca5004170f6f5e482792aad989b0287fe91e5c479403397152f1fa56aa79b156eb47e6c8ea3eb175c34cfb38ad8e772874639b1023d4d01395c94e55831671cc022aa6fa1e02a02c2e4abc776f6960e51f83b71a8c0f207b6a347573977812c9aa5480b0011aa739bd4b76c18c000cc4757cceccb920f007c40c00e37e5ab21476cd9f6054a8fffb55a108f5c706e2cea2049d81fd321ff47d2a5761b0800955ab1d4f4889f55a84e2601c684f17a4ade7453ea49591d0b59c8d9a765052f62219cf6ef4a5dd9539f0617d6ebbebce7c000455475d18449e25c49ef9a1e3efe18c09082ebe2058d7c347defaa92f0664553b805c7d76bbfce5f330aca220ac90a789380fc479ea0d8793205813cca590a912f699ad52f991a1bc0a503c3ec4b2a696719e3c26591a87127f7305cc7e72f4c8e39355ebb06a5b1042990f38710ee7aa612ee4374bb82e878585a70a96c2a6b47f101a4ff154be4fd76a3167577a5cc54d9167c154c69ac35485e44cc898b719e1be3cc9c0fb5624b8f8a0dae10947a41bf848b6c1bb33d1006ec077d7e286e3f2a7b4843716390119449fe2721e81a5ed2333d331c7120765da58fadae73c19d9a8c4509cf8ac1e9d98b799a5274509069739b5823f3fb496663820033426988eefca53e580e0f9e0dfe0992fc2e53a97e053639f98577058f995bdbd41cefdba50102032620012158203b8176b7504489cc593046d7988abb7905a742de6ac2cdc748a873c663e90cb12258201436d5edc9a75f23999eef9d5950a5c2455514ee1014084720f841a06b828a11'
认证:
challenge = h'ef1deba56dce48f674a447ccf63b9599258ce87648e5c396f2ef0ca1da460e3b' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='none.ES256.long-credential-id', L=32) 得出 client_data_gen_flags = h'80' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='none.ES256.long-credential-id', L=1) 得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data ; auth_data_UV_BS 设置认证器数据标志中的 UV 和 BS 位,仅当注册时 BE 为 1 时才设置 BS auth_data_UV_BS = h'e5' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='none.ES256.long-credential-id', L=1) 得出 authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50d00000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22377833727057334f53505a307045664d396a75566d53574d36485a4935634f573875384d6f647047446a73222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' signature = h'304502203ecef83fb12a0cae7841055f9f87103a99fd14b424194bbf06c4623d3ee6e3fd022100d2ace346db262b1374a6b70faa51f518a42ddca13a4125ce6f5052a75bac9fb6'
16.1.6. ES256 凭据的 Packed 类型 Attestation
注册:
challenge = h'c1184a5fddf8045e13dc47f54b61f5a656b666b59018f16d870e9256e9952012' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.ES256', L=32) 推导得出 credential_private_key = h'36ed7bea2357cefa8c4ec7e134f3312d2e6ca3058519d0bcb4c1424272010432' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.ES256', L=32) 推导得出 client_data_gen_flags = h'8d' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.ES256', L=1) 推导得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data extra_client_data = h'f5af1b3588ca0a05ab05753e7c29756a' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.ES256', L=16) 推导得出 aaguid = h'876ca4f52071c3e9b25509ef2cdf7ed6' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.ES256', L=16) 推导得出 credential_id = h'c9a6f5b3462d02873fea0c56862234f99f081728084e511bb7760201a89054a5' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.ES256', L=32) 推导得出 ; auth_data_UV_BE_BS 决定 authenticator data flag 中的 UV、BE 和 BS 位,BS 仅在 BE 为 1 时置位 auth_data_UV_BE_BS = h'4f' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.ES256', L=1) 推导得出 attestation_private_key = h'ec2804b222552b4b277d1f58f8c4343c0b0b0db5474eb55365c89d66a2bc96be' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.ES256', L=32) 推导得出 attestation_cert_serial_number = h'88c220f83c8ef1feafe94deae45faad0' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.ES256', L=16) 推导得出 clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a227752684b58393334424634543345663153324831706c61325a725751475046746877365356756d56494249222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20396138624e596a4b436757724258552d66436c3161673d3d227d' attestationObject = h'a363666d74667061636b65646761747453746d74a363616c67266373696758473045022025fcee945801b94e63d7c029e6f761654cf02e7100d5364a3b90e03daa6276fc022100eabcdf4ce19feb0980e829c3b6137079b18e42f43ce5c3c573b83368794f354c637835638159022530820221308201c8a00302010202110088c220f83c8ef1feafe94deae45faad0300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004a91ba4389409dd38a428141940ca8feb1ac0d7b4350558104a3777a49322f3798440f378b3398ab2d3bb7bf91322c92eb23556f59ad0a836fec4c7663b0e4dc3a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414a589ba72d060842ab11f74fb246bdedab16f9b9b301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d040302034700304402201726b9d85ecd8a5ed51163722ca3a20886fd9b242a0aa0453d442116075defd502207ef471e530ac87961a88a7f0d0c17b091ffc6b9238d30f79f635b417be5910e768617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54d00000000876ca4f52071c3e9b25509ef2cdf7ed60020c9a6f5b3462d02873fea0c56862234f99f081728084e511bb7760201a89054a5a50102032620012158201cf27f25da591208a4239c2e324f104f585525479a29edeedd830f48e77aeae522582059e4b7da6c0106e206ce390c93ab98a15a5ec3887e57f0cc2bece803b920c423'
认证:
challenge = h'b1106fa46a57bef1781511c0557dc898a03413d5f0f17d244630c194c7e1adb5' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.ES256', L=32) 推导得出 client_data_gen_flags = h'75' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.ES256', L=1) 推导得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data extra_client_data = h'019330c8cc486c3f3eba0b85369eabf1' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='packed.ES256', L=16) 推导得出 ; auth_data_UV_BS 设置 authenticator data flag 中的 UV 和 BS 位,但仅当注册时 BE 被置位时才设置 BS 位 auth_data_UV_BS = h'46' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0c', info='packed.ES256', L=1) 推导得出 authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50d00000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2273524276704770587676463446524841565833496d4b4130453958773858306b526a44426c4d6668726255222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20415a4d77794d78496244382d756775464e70367238513d3d227d' signature = h'30460221009d8d54895393894d37b9fa7bdfbcff05403de3cf0d6443ffb394fa239f101579022100c8871288f19c6c48a3b64c09d39868c12d16ed80ea4c5d8890288975c0272f50'
16.1.7. ES384 凭据的 Packed 类型 Attestation
注册:
challenge = h'567b030b3e186bc1d169dd45b79f9e0d86f1fd63474da3eade5bdb8db379a0c3' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.ES384', L=32) 推导得出 credential_private_key = h'271e37d309c558c0f35222b37abba7500377d68e179e4c74b0cb558551b2e5276b47b90a317ca8ebbe1a12c93c2d5dd9' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.ES384', L=48) 推导得出 client_data_gen_flags = h'32' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.ES384', L=1) 推导得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data aaguid = h'e950dcda3bdae1d087cda380a897848b' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.ES384', L=16) 推导得出 credential_id = h'953ae2dd9f28b1a1d5802c83e1f65833bb9769a08de82d812bc27c13fc6f06a9' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.ES384', L=32) 推导得出 ; auth_data_UV_BE_BS 决定 authenticator data flag 中的 UV、BE 和 BS 位,BS 仅在 BE 为 1 时置位 auth_data_UV_BE_BS = h'db' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.ES384', L=1) 推导得出 attestation_private_key = h'8d979fbb6e49c4eeb5925a2bca0fcdb023d3fb90bcadce8391da9da4ed2aee9a' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.ES384', L=32) 推导得出 attestation_cert_serial_number = h'3d0a5588bb87ebb1d4cee4a1807c1b7c' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.ES384', L=16) 推导得出 clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22566e7344437a3459613848526164314674352d65445962785f574e4854615071336c76626a624e356f4d4d222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' attestationObject = h'a363666d74667061636b65646761747453746d74a363616c67266373696758473045022100c56ecc970b7843833e0f461fde26233f61eb395161d481558c08b9c6ed61675b022029f5e05033705cd0f9b0a07e149468ec308a4f84906409efdceb1da20a7518d6637835638159022530820221308201c7a00302010202103d0a5588bb87ebb1d4cee4a1807c1b7c300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d0301070342000417e5cc91d676d370e36aa7de40c25aacb45a3845f13d2932088ece2270b9b431241c219c22d0c256c9438ade00f2c05e62f8ef906b9b997ae9f3c460c2db66f5a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414c7c8dd95382a2230e4c0dd3664338fa908169a9c301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020348003045022054068cc9ae038937b7c468c307edb9c6927ffdeb6a20070c483eb40330f99f10022100cf41953919c3c04693d6b1f42a613753f204e70e85fc6e9b17036170b83596e068617574684461746158c5bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55900000000e950dcda3bdae1d087cda380a897848b0020953ae2dd9f28b1a1d5802c83e1f65833bb9769a08de82d812bc27c13fc6f06a9a5010203382220022158304866bd8b01da789e9eb806e5eab05ae5a638542296ab057a2f1bbce9b58f8a08b9171390b58a37ac7fffc2c5f45857da2258302a0b024c7f4b72072a1f96bd30a7261aae9571dd39870eb29e55c0941c6b08e89629a1ea1216aa64ce57c2807bf3901a'
认证:
challenge = h'ff41c3d25dbd8966fb61e28ef5e47041e137ed268520412d76202ba0ad2d1453' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.ES384', L=32) 推导得出 client_data_gen_flags = h'0c' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.ES384', L=1) 推导得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data ; auth_data_UV_BS 设置 authenticator data flag 中的 UV 和 BS 位,但仅当注册时 BE 被置位时才设置 BS 位 auth_data_UV_BS = h'af' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.ES384', L=1) 推导得出 authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50d00000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a225f304844306c32396957623759654b4f39655277516545333753614649454574646941726f4b307446464d222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' signature = h'3065023100e4efbb46745ed00e67c4d51ab2bacab2af62ffa8b7c5fecec6d7d9bf2582275034a713a3dd731685eee81adfaf6aa63f0230161655353f07e018a3c2539f8de7c8c4cf88d4c32d2be29fe4e76fa096ecc9458bbfe0895d57129ab324130e6f0692db'
16.1.8. ES512 凭据的 Packed 类型 Attestation
注册:
challenge = h'4ee220cd92b07e11451cb4c201c5755bd879848e492a9b12d79135c62764dc2fd28ead4808cafe5ad1de8fa9e08d4a8eeafea4dfb333877b02bc503f475d3b0c1394a7683baaf4f2477829f7b8cf750948985558748c073068396fcfdcd3f245bf2038e6bb38d7532768aad13be8c118f727722e7426139041e9caca503884c5' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.ES512', L=128) 推导得出 credential_private_key = h'f11120594f6a4944ac3ba59adbbc5b85016895b649f4cc949a610f4b48be47b318850bacb105f747647bba8852b6b8e52a0b3679f1bbbdfe18c99409bcb644fa45' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.ES512', L=65) 推导得出 client_data_gen_flags = h'6d' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.ES512', L=1) 推导得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data extra_client_data = h'a37a958ce2f6b535a6e06c64cc8fd082' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.ES512', L=16) 推导得出 aaguid = h'39d8ce6a3cf61025775083a738e5c254' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.ES512', L=16) 推导得出 credential_id = h'd17d5af7e3f37c56622a67c8462c9e1c6336dfccb8b61d359dc47378dba58ce4' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.ES512', L=32) 推导得出 ; auth_data_UV_BE_BS 决定 authenticator data flag 中的 UV、BE 和 BS 位,BS 仅在 BE 为 1 时置位 auth_data_UV_BE_BS = h'cf' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.ES512', L=1) 推导得出 attestation_private_key = h'ffbc89d5f75994f52dc5e7538ee269402d26995d40c16fb713473e34fca98be4' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.ES512', L=32) 推导得出 attestation_cert_serial_number = h'8a128b7ebe52b993835779e6d9b81355' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.ES512', L=16) 推导得出 clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22547549677a5a4b7766684646484c544341635631573968356849354a4b707353313545317869646b33435f536a713149434d722d577448656a366e676a55714f3676366b33374d7a683373437646415f5231303744424f5570326737717654795233677039376a5064516c496d465659644977484d47673562385f63305f4a46767941343572733431314d6e614b72524f2d6a424750636e636935304a684f5151656e4b796c4134684d55222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a206f3371566a4f4c327454576d3447786b7a495f5167673d3d227d' attestationObject = h'a363666d74667061636b65646761747453746d74a363616c67266373696758483046022100c48fcbd826bbc79680802026688d41ab6da8c3a1d22ab6cecf36c8d7695d22500221008767dfe591277e973078d5692c8c35cf9d579792822e7145c96a0ac4515df5b0637835638159022730820223308201c8a0030201020211008a128b7ebe52b993835779e6d9b81355300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004940b68885291536e2f7c60c05acfb252e7eebcf4304425dd93ab7b1962f20492bf18dc0f12862599e81fb764ac92151f9a78fcbb35d7a26c8c52949b18133c06a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e041604143ffad863abcd3dc5717b8a252189f41af97e7f31301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020349003046022100832c8b64c4f0188bd32e1bec63e13301cdc03165d3ef840d1f3dabb9a5719f83022100add57a9d5bedec98f29222dfc97ea795d055ee13a02a153d02be9ce00aedeb9168617574684461746158e9bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54d0000000039d8ce6a3cf61025775083a738e5c2540020d17d5af7e3f37c56622a67c8462c9e1c6336dfccb8b61d359dc47378dba58ce4a5010203382320032158420083240a2c3ad21a3dc0a6daa3d8bc05a46d7cd9825ba010ae2a22686c2d6d663d7d5f678987fb1e767542e63dc197ae915e25f8ee284651af29066910a2cc083f50225842017337df47ab5cce5d716ef8caffa97a3012689b1f326ea6c43a1ba9596c72f71f0122390143552b42be772b4c35ffb961220c743b486a601ea4cb6d5412f5b078d3'
认证:
challenge = h'08d3190c6dcb3d4f0cb659a0333bf5ea124ddf36a0cd33d5204b0d7a22a8cc26f2e4f169d200285c77b3fb22e0f1c7f49a87d4be2d25e92d797808ddaaa9b5715efd3a6ada9339d3052a687dbc5d2f8c871b0451e0691f57ad138541b7b72e7aa8933729ec1c664bf2e4dedae1616d08ecefa80a2a53b103663ce5a881048829' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.ES512', L=128) 推导得出 client_data_gen_flags = h'ac' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.ES512', L=1) 推导得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data ; auth_data_UV_BS 设置 authenticator data flag 中的 UV 和 BS 位,但仅当注册时 BE 被置位时才设置 BS 位 auth_data_UV_BS = h'52' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='packed.ES512', L=1) 推导得出 authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b51900000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22434e4d5a4447334c5055384d746c6d674d7a763136684a4e337a61677a5450564945734e65694b6f7a436279355046703067416f5848657a2d794c67386366306d6f66557669306c3653313565416a6471716d31635637394f6d72616b7a6e544253706f666278644c3479484777525234476b66563630546855473374793536714a4d334b6577635a6b7679354e376134574674434f7a7671416f71553745445a6a7a6c7149454569436b222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' signature = h'3081870242009bda02fe384e77bcb9fb42b07c395b7a53ec9d9616dd0308ab8495c2141c8364c7d16e212a4a4fb8e3987ff6c99eafd64d8484fd28c3fc7968f658a9033d1bb1b802416383e9f3ee20c691b66620299fef36bea2df4d39c92b2ead92f58e7b79ab0d9864d2ebf3b0dcc66ea13234492ccee6e9d421db43c959bcb94c162dc9494136c9f6'
16.1.9. RS256 凭据的 Packed 类型 Attestation
注册:
challenge = h'bea8f0770009bd57f2c0df6fea9f743a27e4b61bbe923c862c7aad7a9fc8e4a6' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.RS256', L=32) 推导得出 ; 两个最小的梅森素数 2^p - 1,p >= 1024 private_key_p = 2 ^ 1279 -1 = h'7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' private_key_q = 2 ^ 2203 -1 = h'07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' client_data_gen_flags = h'1c' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.RS256', L=1) 推导得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data aaguid = h'428f8878298b9862a36ad8c7527bfef2' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.RS256', L=16) 推导得出 credential_id = h'992a18acc83f67533600c1138a4b4c4bd236de13629cf025ed17cb00b00b74df' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.RS256', L=32) 推导得出 ; auth_data_UV_BE_BS 决定 authenticator data flag 中的 UV、BE 和 BS 位,BS 仅在 BE 为 1 时置位 auth_data_UV_BE_BS = h'7e' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.RS256', L=1) 推导得出 attestation_private_key = h'08a1322d5aa5b5b40cd67c2cc30b038e7921d7888c84c342d50d79f0c5fc3464' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.RS256', L=32) 推导得出 attestation_cert_serial_number = h'1f6fb7a5ece81b45896b983a995da5f3' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.RS256', L=16) 推导得出 clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a2276716a776477414a76566679774e3976367039304f69666b7468752d6b6a79474c48717465705f49354b59222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' attestationObject = h'a363666d74667061636b65646761747453746d74a363616c672663736967584730450221008b8c5c6ea8c142c032e0be69e1353d44461c5c9109941cdda951b976eb95b6b302204d52f406c19e254b3ff9589bd18070fb055ac8db12fdd0a6734bea9d7168e900637835638159022630820222308201c7a00302010202101f6fb7a5ece81b45896b983a995da5f3300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004b7b36b7542a11120b443c794d0c99fdc25a06b76586413d81e086163ef6fe147a557afc34e2861d9057d6d465d4705a0310550bdeeb5f35ee35b9425ab859981a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414fb37b647bccfb9e54d989eaaacc1633868703fb3301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020349003046022100b86bc129d92afca7d9869a39f70f139a305b4073a39eb654d81424bed5757d91022100cf9f7c60cab7c4a7d3e7f0020f281a93d4fd0a9f95121b989f56932a68885fba68617574684461746159021bbfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55d00000000428f8878298b9862a36ad8c7527bfef20020992a18acc83f67533600c1138a4b4c4bd236de13629cf025ed17cb00b00b74dfa4010303390100205901b403fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012143010001'
认证:
challenge = h'295f59f5fa8fe62c5aca9e27626c78c8da376ae6d8cd2dd29aebad601e1bc4c5' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.RS256', L=32) 推导得出 client_data_gen_flags = h'0e' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.RS256', L=1) 推导得出 ; 仅当 client_data_gen_flags 的 0x01 位为 1 时,才包含 extra_client_data ; auth_data_UV_BS 设置 authenticator data flag 中的 UV 和 BS 位,但仅当注册时 BE 被置位时才设置 BS 位 auth_data_UV_BS = h'ba' ; 由 HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.RS256', L=1) 推导得出 authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b51900000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a224b56395a39667150356978617970346e596d7834794e6f33617562597a5333536d75757459423462784d55222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' signature = h'01063d52d7c39b4d432fc7063c5d93e582bdcb16889cd71f888d67d880ea730a428498d3bc8e1ee11f2b1ecbe6c292b118c55ffaaddefa8cad0a54dd137c51f1eec673f1bb6c4d1789d6826a222b22d0f585fc901fdc933212e579d199b89d672aa44891333e6a1355536025e82b25590256c3538229b55737083b2f6b9377e49e2472f11952f79fdd0da180b5ffd901b4049a8f081bb40711bef76c62aed943571f2d0575304cb549d68d8892f95086a30f93716aee818f8dc06e96c0d5e0ed4cfa9fd8773d90464b68cf140f7986666ff9c9e3302acd0535d60d769f465e2ab57ef8aabc89fccfef7ba32a64154a8b3d26be2298f470b8cc5377dbe3dfd4b0b45f8f01e63bde6cfc76b62771f9b70aa27cf40152cad93aa5acd784fd4b90f676e2ea828d0bf2400aebbaae4153e5838f537f88b6228346782a93a899be66ec77de45b3efcf311da6321c92e6b0cd11bfe653bf3e98cee8e341f02d67dbb6f9c98d9e8178090cfb5b70fbc6d541599ac794ae2f1d4de1286ec8de8c2daf7b1d15c8438e90d924df5c19045220a4c8438c1b979bbe016cf3d0eeec23c3999d4882cc645b776de930756612cdc6dd398160ff02a6'
16.1.10. 打包声明(使用 Ed25519 凭据)
注册:
challenge = h'560c73a09ce7a1586d61c1d6e41fef149be523e220fc9f385d38ab23702ebf1b' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='packed.Ed25519', L=32) private_key = h'c87fce9e9cd283d272a2418d9683366f83661e458ad4451f0f1c95cb83b0f0a8' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='packed.Ed25519', L=32) client_data_gen_flags = h'41' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='packed.Ed25519', L=1) ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data extra_client_data = h'db7587e24b9187edb77933754331e443' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='packed.Ed25519', L=16) aaguid = h'164009ea09faae7c397bc3e2ad0e7ec0' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='packed.Ed25519', L=16) credential_id = h'c6cffa01b7fda368a7e0b29c1384a719820246bca894dd12914708743af0cecd' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='packed.Ed25519', L=32) ; auth_data_UV_BE_BS 决定 authenticator data 标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS auth_data_UV_BE_BS = h'e8' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='packed.Ed25519', L=1) attestation_private_key = h'673ee7fd94405de523fd84a088ab082d75b7fceef02a301e2bca0a28537cf243' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='packed.Ed25519', L=32) attestation_cert_serial_number = h'6e391f23f57150dc7a12dad18f2b43ad' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='packed.Ed25519', L=16) clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a225667787a6f4a7a6e6f5668745963485735425f76464a766c492d49675f4a38345854697249334175767873222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a2032335748346b7552682d323365544e31517a486b51773d3d227d' attestationObject = h'a363666d74667061636b65646761747453746d74a363616c672663736967584730450220730a54d4f76cb1f2b7dd4a5a6eee3374e3c8a60fb3c4daa527c9277e365b64aa0221008b31a04a28cc4148b14c42a916548ee7f430bc7629295b42ee93e5d1aaba8ee6637835638159022530820221308201c7a00302010202106e391f23f57150dc7a12dad18f2b43ad300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d03010703420004fb96a581a0b36742a8c45d6ffb5af1ef155524b50339445ec1109874045e0087db77edef91f3dc949927470d84b01627087b72c86b7c9d02e1389cba680ffc36a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414ef2ce1a86caba85121130a16e8ce82a75d5a6653301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d0403020348003045022100ad4fa628cffba5a642a562cbfefe63efecce26d90c80114114d1745383e12f01022028af87ba3b0ff868a34b9458bc6973b27380a328dd87b7436651ffa823280bca6861757468446174615881bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54900000000164009ea09faae7c397bc3e2ad0e7ec00020c6cffa01b7fda368a7e0b29c1384a719820246bca894dd12914708743af0cecda401010327200621582089f81eba4a1f510cb243ff7fb9e9cf899bf627e49ce1ac3c3eae8adb2a8d7d7b'
认证:
challenge = h'3790da8b2b72ee8ce19761787ad38cbfaa697eb3ca013a1342988756b98785ab' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='packed.Ed25519', L=32) client_data_gen_flags = h'de' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='packed.Ed25519', L=1) ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data ; auth_data_UV_BS 设置 authenticator data 标志的 UV 和 BS 位,但仅当注册时设置了 BE 时,才会设置 BS auth_data_UV_BS = h'18' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='packed.Ed25519', L=1) authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b51900000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a224e35446169797479376f7a686c32463465744f4d763670706672504b41546f545170694856726d48686173222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' signature = h'4c873571377ac019f257d6bf07249f63ac2487483c51bc511ce0f0e3266c840cb07a09cdc445a2f963d8603a9f0f6cf9ce709d7fc6a96c7c51ea08d33776010c'
16.1.11. TPM 声明(使用 ES256 凭据)
注册:
challenge = h'cfc82cdf1ceee876120aa88f0364f0910193460cfb97a317b2fe090694f9a299' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='tpm.ES256', L=32) credential_private_key = h'80c60805e564f6d33e7abdff9d32e3db09a6219fe378a268d23107191b18e39f' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='tpm.ES256', L=32) client_data_gen_flags = h'84' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='tpm.ES256', L=1) ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data aaguid = h'4b92a377fc5f6107c4c85c190adbfd99' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='tpm.ES256', L=16) credential_id = h'ec27bec7521c894bbb821105ea3724c90e770cf1fa354157ef18d0f18f78bea9' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='tpm.ES256', L=32) ; auth_data_UV_BE_BS 决定 authenticator data 标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS auth_data_UV_BE_BS = h'af' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='tpm.ES256', L=1) attestation_private_key = h'6210f09e0ce7593e851a880a4bdde2d2192afeac46104abce1a890a5a71cf0c6' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='tpm.ES256', L=32) attestation_cert_serial_number = h'311fc42da0ab10c43a9b1bf3a75e34e2' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='tpm.ES256', L=16) clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a227a38677333787a753648595343716950413254776b51475452677a376c364d587376344a427054356f706b222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' attestationObject = h'a363666d746374706d6761747453746d74a663616c67266373696758463044022066e5826a652091030fd444e33c3eca2bc6dc548cf3045013addb38aa6457a21002203f3a5c95c9e707d0e555041bcc8698ee4ebc04e26cc8bae459705471789851766376657263322e30637835638159023a30820236308201dca0030201020210311fc42da0ab10c43a9b1bf3a75e34e2300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d03010703420004c54e3f109094f60d7699b7db5d838569ffd1f3e1c9e897cd9eb40063f9402e3e9937e936cf1fcd5eb743ff443c97ab2edcd7c8e0e6cf6cfd413b8ab19fffa769a381d33081d0300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e041604145f546cb6973d4981e80fcdc7463859f5879680e4301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e30100603551d250409300706056781050803305e0603551d110101ff04543052a450304e314c3014060567810502010c0b69643a30303030303030303014060567810502030c0b69643a3030303030303030301e060567810502020c15576562417574686e207465737420766563746f7273300a06082a8648ce3d0403020348003045022063c9a2797b8066f1db34dd609f1ab6695607e7a98e9ff8090a68853c9a9fc949022100a55831a39f5b8a2aa9a68837829cabf43fea2a5cea4859ae851cac78e6ac3e97677075624172656158560023000b0004000000000010001000030010002041202698c9d9753fb4bb3f27cd09fe6b8afdb76438ee2ae54d7c9dade10d864b0020d8735115cdb330a63ea1d6e43d5000f4bd56f99bce83ee1d73301fc270116d076863657274496e666f5869ff544347801700000020277d0e05579dd013215a62273f7f3a3e7e191ead2654a3036d75a5a3ee37a6b0000000000000000011111111222222223300000000000000000022000b9c42d8aad5939331b9af3711af179f17123178098c9a7d0ca89fcd1fc800f3c7000068617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54d000000004b92a377fc5f6107c4c85c190adbfd990020ec27bec7521c894bbb821105ea3724c90e770cf1fa354157ef18d0f18f78bea9a501020326200121582041202698c9d9753fb4bb3f27cd09fe6b8afdb76438ee2ae54d7c9dade10d864b225820d8735115cdb330a63ea1d6e43d5000f4bd56f99bce83ee1d73301fc270116d07'
认证:
challenge = h'00093b66c21d5b5e89f7a07082118907ea3e502d343b314b8c5a54d62db202fb' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='tpm.ES256', L=32) client_data_gen_flags = h'86' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='tpm.ES256', L=1) ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data ; auth_data_UV_BS 设置 authenticator data 标志的 UV 和 BS 位,但只有在注册时 BE 被设置时才设置 BS auth_data_UV_BS = h'87' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='tpm.ES256', L=1) authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50d00000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a2241416b375a7349645731364a393642776768474a422d6f2d554330304f7a464c6a46705531693279417673222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' signature = h'3045022060dc76b1607ec716c6e5eba8d056695ed6bc47b2e3d7a729c34e759e3ab66aa0022100d010a9e8fddcb64c439dfdca628ddb33cf245d567d157d9f66f942601bed9b38'
16.1.12. Android Key 声明(使用 ES256 凭据)
注册:
challenge = h'3de1f0b7365dccde3ff0cbf25e26ffa7baff87ef106c80fc865dc402d9960050' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='android-key.ES256', L=32) credential_private_key = h'd4328d911acb0ebcc42aad29b29ffb55d5bc31d8af7ca9a16703d56c21abc7b4' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='android-key.ES256', L=32) client_data_gen_flags = h'73' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='android-key.ES256', L=1) ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data extra_client_data = h'555d5c42e476a8b33f6a63dfa07ccbd2' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='android-key.ES256', L=16) aaguid = h'ade9705e1ce7085b899a540d02199bf8' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='android-key.ES256', L=16) credential_id = h'0a4729519788b6ed8a2d772b494e186244d8c798c052960dbc8c10c915176795' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='android-key.ES256', L=32) ; auth_data_UV_BE_BS 决定 authenticator data 标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS auth_data_UV_BE_BS = h'1e' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='android-key.ES256', L=1) attestation_cert_serial_number = h'1ff91f76b63f44812f998b250b0286bf' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='android-key.ES256', L=16) clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a2250654877747a5a647a4e345f384d76795869625f7037725f682d385162494438686c334541746d57414641222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a205656316351755232714c4d5f616d50666f487a4c30673d3d227d' attestationObject = h'a363666d746b616e64726f69642d6b65796761747453746d74a363616c672663736967584630440220592bbc3c4c5f6158b52be1e085c92848986d7844245dfc9512e1a7e9ff7a2cd8022015bdd0852d3bd091e1c22da4211f4ccf0fdf4d912599d1c6630b1f310d3166f5637835638159026d3082026930820210a00302010202101ff91f76b63f44812f998b250b0286bf300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d0301070342000499169657036d089a2a9821a7d0063d341f1a4613389359636efab5f3cbf1accfdd91c55543176ea99b644406dd1dd63774b6af65ac759e06ff40b1c8ab02df6ba381a83081a5300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e041604141ac81e50641e8d1339ab9f7eb25f0cd5aac054b0301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e3045060a2b06010401d679020111043730350202012c0201000201000201000420b20e943e3a7544b3a438943b6d5655313a47ef1af34e00ff3261aeb9ed155817040030003000300a06082a8648ce3d040302034700304402206f4609c9ffc946c418cef04c64a0d07bcce78f329b99270b822f2a4d1e3b75330220093c8d18328f36ef157f296393bdc7721dd2bd67438ffeaa42f051a044b7457168617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b55d00000000ade9705e1ce7085b899a540d02199bf800200a4729519788b6ed8a2d772b494e186244d8c798c052960dbc8c10c915176795a501020326200121582099169657036d089a2a9821a7d0063d341f1a4613389359636efab5f3cbf1accf225820dd91c55543176ea99b644406dd1dd63774b6af65ac759e06ff40b1c8ab02df6b'
认证:
challenge = h'e4ee05ca9dbced74116540f24ed9adc62aae8507560522844ffa7eea14f7af86' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='android-key.ES256', L=32) client_data_gen_flags = h'43' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='android-key.ES256', L=1) ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data extra_client_data = h'ab127107eff182bc3230beb5f1dad29c' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='android-key.ES256', L=16) ; auth_data_UV_BS 设置 authenticator data 标志的 UV 和 BS 位,但只有在注册时 BE 被设置时才设置 BS auth_data_UV_BS = h'4a' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0b', info='android-key.ES256', L=1) authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50900000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22354f344679703238375851525a55447954746d74786971756851645742534b45545f702d36685433723459222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a2071784a78422d5f78677277794d4c3631386472536e413d3d227d' signature = h'304502202060107d953b286aa1bf35e3e8c78b383fddab5591b2db17ffb23ed83fe7df20022100a99be0297cb0d9d38aa96f30b760a4e0749dab385acd2a51d0560caae570d225'
16.1.13. Apple 匿名声明(使用 ES256 凭据)
注册:
challenge = h'f7f688213852007775009cf8c096fda89d60b9a9fb5a50dd81dd9898af5a0609' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='apple.ES256', L=32) credential_private_key = h'de987bd9d43eeb44728ce0b14df11209dff931fb56b5b1948de4c0da1144ded0' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='apple.ES256', L=32) client_data_gen_flags = h'5f' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='apple.ES256', L=1) ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data extra_client_data = h'4e32cf9e939a5d052b14d71b1f6b5364' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='apple.ES256', L=16) aaguid = h'748210a20076616a733b2114336fc384' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='apple.ES256', L=16) credential_id = h'9c4a5886af9283d9be3e9ec55978dedfdce2e3b365cab193ae850c16238fafb8' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='apple.ES256', L=32) ; auth_data_UV_BE_BS 决定 authenticator data 标志中的 UV、BE 和 BS 位,但只有在设置了 BE 时才设置 BS auth_data_UV_BE_BS = h'2a' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='apple.ES256', L=1) attestation_cert_serial_number = h'394275613d5310b81a29ce90f48b61c1' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='apple.ES256', L=16) clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22395f61494954685341486431414a7a34774a6239714a316775616e37576c4464676432596d4b396142676b222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73652c22657874726144617461223a22636c69656e74446174614a534f4e206d617920626520657874656e6465642077697468206164646974696f6e616c206669656c647320696e20746865206675747572652c207375636820617320746869733a20546a4c506e704f6158515572464e6362483274545a413d3d227d' attestationObject = h'a363666d74656170706c656761747453746d74a1637835638159025c30820258308201fea0030201020210394275613d5310b81a29ce90f48b61c1300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d030107034200048a3d5b1b4c543a706bf6e4b00afedb3c930b690dd286934fe2911f779cc7761af728e1aa3b0ff66692192daa776b83ddf8e3340d2d9a0eabdfc324eb3e2f136ca38196308193300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e0416041412f1ce6c0ae39b403bfc9200317bc183a4e4d766301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e303306092a864886f76364080204263024a122042097851a1a98b69c0614b26a94b70ec3aa07c061f89dbee23fbee01b6c42d718b0300a06082a8648ce3d040302034800304502207d541a5553f38b93b78b26a9dca58e64a7f8fac15ca206ae3ea32497cda375fb0221009137c6b75e767ec08224b29a7f703db4b745686dcc8a26b66e793688866d064f68617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54900000000748210a20076616a733b2114336fc38400209c4a5886af9283d9be3e9ec55978dedfdce2e3b365cab193ae850c16238fafb8a50102032620012158208a3d5b1b4c543a706bf6e4b00afedb3c930b690dd286934fe2911f779cc7761a225820f728e1aa3b0ff66692192daa776b83ddf8e3340d2d9a0eabdfc324eb3e2f136c'
认证:
challenge = h'd3eb2964641e26fed023403a72dde093b19c4ba9008c3f9dd83fcfd347a66d05' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='apple.ES256', L=32) client_data_gen_flags = h'c2' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='apple.ES256', L=1) ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data ; auth_data_UV_BS 设置 authenticator data 标志的 UV 和 BS 位,但只有在注册时 BE 被设置时才设置 BS auth_data_UV_BS = h'e2' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'0a', info='apple.ES256', L=1) authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50900000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22302d73705a4751654a76375149304136637433676b37476353366b416a442d6432445f503030656d625155222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' signature = h'3046022100ee35db795ce28044e1f8231d68b3d79a9882f7415aa35c1b5ac74d24251073c8022100dcc65691650a412d0ceef843710c09827acf26c7845bddac07eec95863e7fc4c'
16.1.14. FIDO U2F 声明(使用 ES256 凭据)
注册:
challenge = h'e074372990b9caa507a227dfc67b003780c45325380d1a90c20f81ed7d080c06' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'00', info='fido-u2f.ES256', L=32) credential_private_key = h'51bd002938fa10b83683ac2a2032d0a7338c7f65a90228cfd1f61b81ec7288d0' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'01', info='fido-u2f.ES256', L=32) client_data_gen_flags = h'00' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'02', info='fido-u2f.ES256', L=1) ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data aaguid = h'afb3c2efc054df425013d5c88e79c3c1' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'03', info='fido-u2f.ES256', L=16) credential_id = h'a4ba6e2d2cfec43648d7d25c5ed5659bc18f2b781538527ebd492de03256bdf4' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'04', info='fido-u2f.ES256', L=32) attestation_private_key = h'66fda477a2a99d14c5edd7c1041a297ba5f3375108b1d032b79429f42349ce33' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'05', info='fido-u2f.ES256', L=32) attestation_cert_serial_number = h'04f66dc6542ea7719dea416d325a2401' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'06', info='fido-u2f.ES256', L=16) clientDataJSON = h'7b2274797065223a22776562617574686e2e637265617465222c226368616c6c656e6765223a22344851334b5a4335797155486f696666786e73414e344445557955344452715177672d4237583049444159222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' attestationObject = h'a363666d74686669646f2d7532666761747453746d74a26373696758473045022100f41887a20063bb26867cb9751978accea5b81791a68f4f4dd6ea1fb6a5c086c302204e5e00aa3895777e6608f1f375f95450045da3da57a0e4fd451df35a31d2d98a637835638159022530820221308201c7a003020102021004f66dc6542ea7719dea416d325a2401300a06082a8648ce3d0403023062311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331253023060355040b0c1c41757468656e74696361746f72204174746573746174696f6e204341310b30090603550406130241413020170d3234303130313030303030305a180f33303234303130313030303030305a305f311e301c06035504030c15576562417574686e207465737420766563746f7273310c300a060355040a0c0357334331223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130241413059301306072a8648ce3d020106082a8648ce3d0301070342000456fffa7093dede46aefeefb6e520c7ccc78967636e2f92582ba71455f64e93932dff3be4e0d4ef68e3e3b73aa087e26a0a0a30b02dc2aa2309db4c3a2fc936dea360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414420822eb1908b5cd3911017fbcad4641c05e05a3301f0603551d2304183016801445aff715b0dd786741fee996ebc16547a3931b1e300a06082a8648ce3d040302034800304502200d0b777f0a0b181ad2830275acc3150fd6092430bcd034fd77beb7bdf8c2d546022100d4864edd95daa3927080855df199f1717299b24a5eecefbd017455a9b934d8f668617574684461746158a4bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b54100000000afb3c2efc054df425013d5c88e79c3c10020a4ba6e2d2cfec43648d7d25c5ed5659bc18f2b781538527ebd492de03256bdf4a5010203262001215820b0d62de6b30f86f0bac7a9016951391c2e31849e2e64661cbd2b13cd7d5508ad225820503b0bda2a357a9a4b34475a28e65b660b4898a9e3e9bbf0820d43494297edd0'
认证:
challenge = h'f90c612981d84f599438de1a500f76926e92cc84bef8e02c6e23553f00485435' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'07', info='fido-u2f.ES256', L=32) client_data_gen_flags = h'2c' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'08', info='fido-u2f.ES256', L=1) ; 仅当 client_data_gen_flags 的 0x01 位为 1 时才包含 extra_client_data ; auth_data_UV_BS 设置 authenticator data 标志的 UV 和 BS 位,但只有在注册时 BE 被设置时才设置 BS auth_data_UV_BS = h'd1' ; 由以下方式导出: HKDF-SHA-256(IKM='WebAuthn test vectors', salt=h'09', info='fido-u2f.ES256', L=1) authenticatorData = h'bfabc37432958b063360d3ad6461c9c4735ae7f8edd46592a5e0f01452b2e4b50100000000' clientDataJSON = h'7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a222d5178684b59485954316d554f4e3461554139326b6d36537a49532d2d4f417362694e5650774249564455222c226f726967696e223a2268747470733a2f2f6578616d706c652e6f7267222c2263726f73734f726967696e223a66616c73657d' signature = h'304402206172459958fea907b7292b92f555034bfd884895f287a76200c1ba287239137002204727b166147e26a21bbc2921d192ebfed569b79438538e5c128b5e28e6926dd7'
16.2. WebAuthn 扩展的测试向量
本节列出 WebAuthn 扩展 的示例值。
16.2.1. 伪随机函数扩展(prf)
本节列出伪随机函数(prf)扩展的示例值。
由于 prf 扩展与 CTAP2 的 hmac-secret 扩展集成([FIDO-CTAP]),因此示例分为两部分:WebAuthn prf 扩展的示例输入和输出(适用于 WebAuthn 客户端和 WebAuthn 依赖方);以及
WebAuthn prf 扩展与 CTAP2 hmac-secret
扩展之间的映射示例(适用于 WebAuthn 客户端和 WebAuthn 认证器)。
16.2.1.1. Web Authentication API
下面的示例可用于测试 WebAuthn 客户端 实现和 WebAuthn 依赖方 使用 prf 扩展。 这些示例并不详尽。
-
enabled输出在注册(registration)流程中始终存在, 在认证(authentication)流程中则从不出现:// 扩展输入示例: { prf: {} } // navigator.credentials.create() 的示例客户端扩展输出: { prf: { enabled: true } } { prf: { enabled: false } } // navigator.credentials.get() 的示例客户端扩展输出: { prf: {} } -
results输出可能出现在注册或认证流程中, 如果存在eval或evalByCredential输入时:// 扩展输入示例: { 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输出存在且所选 PRF 输入包含second输入时,results.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.2.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'437e065e723a98b2f08f39d8baf7c53ebbb2ed3e746b87576fd81f95def5757cad24be18eaef892e97692e684e07da53' ; 认证器计算: 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'23dde5e3462daf36559b85c4ac5f9656aa9bfd81c1dc2bf8533c8b9f3882854786b4f500e25b4e3d81f7fc7c742362294d92926c883b3fae1a3673246464bf730446e1fa4698c432a9092477c5dde5e3' ; 认证器计算: 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) -
iv(用于单输入 salt_enc 与 PIN 协议 2):截断的SHA-256(seed || 0x07) -
iv(用于双输入 salt_enc 与 PIN 协议 2):截断的SHA-256(seed || 0x08) -
iv(用于单输入 output_enc 与 PIN 协议 2):截断的SHA-256(seed || 0x09) -
iv(用于双输入 output_enc 与 PIN 协议 2):截断的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 Authentication Working Group 联席主席的贡献。
同时感谢 Simone Onofri, Philippe Le Hégaret, Wendy Seltzer, Samuel Weiler, 以及 Harry Halpin 作为我们的 W3C 团队联络人员所作的贡献。
18. 修订历史
本节不具规范效力。
本节简要总结了本规范随时间推移所做的重大更改。
18.1. 自 Web Authentication Level 2 [webauthn-2-20210408] 以来的变更
18.1.1. 实质性变更
对 Web Authentication API 及其操作方式做出了如下更改。
更改:
-
更新了超时建议:§ 15.1 仪式超时的建议范围
-
uvm扩展已不再包含;另见 L2 [webauthn-2-20210408] -
aaguid 字段在 声明的凭据数据 中, 当
attestation偏好为none时不再被清零: § 5.1.3 创建新凭据 - PublicKeyCredential 的 [[Create]](origin, options, sameOriginWithAncestors) 内部方法
弃用项:
-
注册参数
: § 5.4.1 公钥实体说明(字典 PublicKeyCredentialEntity)publicKey.rp.name -
tokenBinding 已更改为 [RESERVED]。
新增功能:
-
新增 JSON (去)序列化方法:
-
支持跨源 iframe 的 create 操作:
-
create 的条件化中介策略:§ 5.1.3 创建新凭据 - PublicKeyCredential 的 [[Create]](origin, options, sameOriginWithAncestors) 内部方法
-
get 的条件化中介策略:§ 5.1.4 使用现有凭据进行断言
-
§ 5.1.7 客户端能力可用性 - PublicKeyCredential 的 getClientCapabilities() 方法
-
新增枚举值
hybrid,见 § 5.8.4 认证器传输枚举(enum AuthenticatorTransport)。 -
新增 客户端数据 属性
topOrigin: § 5.8.1 WebAuthn 签名中所用客户端数据(字典 CollectedClientData)
18.1.2. 编辑性变更
以下更改提升了文档的清晰性、可读性、可导航性等方面。
-
更新了 § 1.2 使用场景 以反映部署生态的发展。
-
澄清了错误条件:
-
§ 6.4 字符串处理拆分为子章节 § 6.4.1.1 客户端截断字符串 和 § 6.4.1.2 认证器截断字符串,以明确责任分工。
-
添加了 § 16 测试向量。
-
将强制性语言移出“note”提示框外。