在尝试使用 AWS Cognito 实现密钥登录时,我找到了 AWS 编写的指南 (https://github.com/aws-samples/webauthn-with-amazon-cognito/)。它展示了如何使用 lambda 触发器来响应挑战并实施流程。我的解决方案在 UI 上使用 React,在 API 上使用 ASP Net,虽然演示代码是使用 Fido2-Lib 库的 Nodejs 实现,但我发现我可以使用 Fido2NetLib 库在 C# 中实现几乎相同的功能。
一切都很顺利,所有移动部分通常都围绕创建和解析凭证进行调整,甚至 Cognito 的 AWS lambda 似乎也运行得很好,直到登录的关键点到来。当公钥和签名得到验证。我首先研究了这个想法,认为密钥采用了意想不到的格式。我意识到演示代码中的 Fido2-Lib 输出 PEM 格式密钥,而 Fido2NetLib 不提供该选项,而是提供 COSE 格式 CBOR 对象(与标准一致 - 不过,在我写这篇文章时,我假设 PEM 密钥来自 Fido2-Lib 的也是 PEM 格式内的 CBOR)。
我仔细检查了密钥的内容,并确保它们都非常标准并且可以被 NodeJS Crypto 接受error:1E08010C:DECODER routines::unsupported
使用这些信息,我编写了一个测试程序来测试验证方法,并尝试添加 PEM 格式(“---- BEGIN PRIVATE KEY ----”),没有喜悦,我尝试了,获取 CBOR 的内容映射私钥并(了解 DER 格式)创建一个 DER 格式密钥,我相信 crypto 可以接受,使用以下示例代码,但没有乐趣,同样的 UNSUPPORTED ROUTINE 错误。
1: 2 - key type Elliptic Curve format
3: -7 - algorithm used ES256
-1: 1 - curve type P-256
-2: buffer(32) - x co-ordinate
-3: buffer(32) - y co-ordinate
我很欣赏这是一个模糊的主题,并尝试修改对 crypto 的验证调用以传递更多参数,了解 Fido2NetLib 中密钥的格式以及它与 Fido2-Lib 的不同之处,我想我应该在这里联系看看如果我遇到一些愚蠢的事情,其他人已经解决了。
但是,我不知道您在哪里“学习”了 DER,但是 您发布的代码并没有创建任何与 DER 类似的东西。它确实将 EC
point 转换为 X9-and-SEC1 格式,这是最常见的标准,并且在 OpenSSL 以及 Nodejs 的 PEM 和 DER 格式中使用,但它本身既不是 PEM 也不是 DER 或甚至是有效的密钥。
如果你有nodejs 16(我希望你有OpenSSL 3),它也支持JOSE中使用的JWK格式,这(并非偶然)更接近COSE。尝试 const coseKey = Buffer.from(publicKeyCredJSON.publicKey, 'base64');
// Parse COSE key
const parsedKey = cbor.decodeFirstSync(coseKey);
// Extract necessary information
const keyType = parsedKey.get(1); // Key type
const algorithm = parsedKey.get(3); // Algorithm
const xCoord = parsedKey.get(-2);
const yCoord = parsedKey.get(-3);// Key value
// Convert key data to buffer
const publicKey = Buffer.concat([Buffer.from([0x04]), xCoord, yCoord]);
// Sample data and signature to verify (replace with your actual data and signature)
const rawAuthnrData = Buffer.from(challengeAnswerJSON.response.authenticatorData, 'base64');
const rawClientData = Buffer.from(challengeAnswerJSON.response.clientDataJSON, 'base64');
// Create verifier
const verifier = crypto.createVerify('SHA256');
// Provide data
verifier.update(rawAuthnrData);
verifier.update(rawClientData);
// Verify signature
const isValid = verifier.verify(publicKey, challengeAnswerJSON.response.signature, 'base64');`
,其中 EC 公钥
RFC7518 规范是
{format:'jwk', key:{perRFC7518}}
,这个 DER 结构实际上是一个固定前缀加上点,您可以从您创建的一次性密钥(也适用于 P-256!)复制固定前缀Nodejs 或 OpenSSL(它们在这里是同一件事)。