Google Titan密钥authData解码失败求助:报错‘Additional info not implemented:29’
Google Titan Key解码AuthData报错“未实现额外信息:29”解决方法
问题描述
应用使用Passkeys功能,通过window.navigator.credentials.create API创建凭证后,获取到包含认证数据(attestation data)的响应,先经CBOR解码得到authData,再尝试用CBOR解码器解码该authData时,Google Titan Key出现解码失败,报错信息:未实现额外信息:29
原因分析
- 核心逻辑错误:AuthData本身不是CBOR格式,它是WebAuthn规范定义的固定二进制结构,仅其中的凭证公钥和扩展数据部分采用CBOR编码。你错误地对整个authData执行CBOR解码,违反了WebAuthn的规范要求。
- 报错中的“29”是十进制扩展ID,对应WebAuthn的
credProtect扩展(十六进制0x1D),用于指定凭证的保护级别。Google Titan Key默认会返回这个扩展字段,但错误的解码逻辑触发了“未实现”的提示。
解决方案
1. 按WebAuthn规范解析AuthData二进制结构
放弃对整个authData的CBOR解码,按照以下步骤拆分解析:
- 固定部分:前32字节为RP ID哈希,接着1字节是标志位,再4字节是签名计数器。
- 可选部分:
- 若标志位包含
AT(0x40),后续为认证凭证数据,其中的凭证公钥需单独进行CBOR解码。 - 若标志位包含
ED(0x80),后续为CBOR格式的扩展数据,其中可能包含ID为29的credProtect扩展。
- 若标志位包含
2. 示例解析代码(JavaScript)
function parseAuthData(authDataBuffer) { const view = new DataView(authDataBuffer); let offset = 0; // 解析RP ID哈希 const rpIdHash = authDataBuffer.slice(offset, offset + 32); offset += 32; // 解析标志位 const flags = view.getUint8(offset); offset += 1; // 解析签名计数器(大端字节序) const signCount = view.getUint32(offset, false); offset += 4; let attestedCredentialData = null; // 处理认证凭证数据(如果AT标志存在) if (flags & 0x40) { const aaguid = authDataBuffer.slice(offset, offset + 16); offset += 16; const credIdLength = view.getUint16(offset, false); offset += 2; const credId = authDataBuffer.slice(offset, offset + credIdLength); offset += credIdLength; // 凭证公钥是CBOR格式,单独解码 const credPublicKey = CBOR.decode(authDataBuffer.slice(offset)); offset += credPublicKey.byteLength; attestedCredentialData = { aaguid, credId, credPublicKey }; } let extensions = null; // 处理扩展数据(如果ED标志存在) if (flags & 0x80) { extensions = CBOR.decode(authDataBuffer.slice(offset)); // 处理credProtect扩展(ID 29) if (extensions[29] !== undefined) { const protectLevel = extensions[29]; // 根据业务需求处理:1=用户验证可选,2=用户验证必需,3=用户验证且凭证不可导出 } } return { rpIdHash, flags, signCount, attestedCredentialData, extensions }; }
3. 解码器适配
确保你的CBOR解码器支持整数类型的键(扩展ID为整数),如果当前解码器不兼容,可替换为cbor-web或@noble/cbor等库;若业务不需要credProtect扩展,也可直接忽略该字段。
内容的提问来源于stack exchange,提问作者Vivek Srivatava
相关产品推荐
相关产品推荐

