Closed vincent-thomas closed 11 months ago
This looks wrong, when you're calling verifyAuthenticationResponse()
:
credentialPublicKey: Buffer.from(body_UNSAFE.id, 'base64url')
You're passing in a credential ID when the method expects the public key you received during registration for that credential ID. Try fixing that value when you call this method and it should solve the problem you're having.
I now did as suggested, and get another error:
⨯ Error: Unexpected end of CBOR data
at checkedRead (webpack-internal:///(rsc)/../../node_modules/.pnpm/cbor-x@1.5.6/node_modules/cbor-x/decode.js:225:25)
at Encoder.decodeMultiple (webpack-internal:///(rsc)/../../node_modules/.pnpm/cbor-x@1.5.6/node_modules/cbor-x/decode.js:188:33)
at Module.decodeFirst (webpack-internal:///(rsc)/../../node_modules/.pnpm/@simplewebauthn+server@8.3.5/node_modules/@simplewebauthn/server/esm/helpers/iso/isoCBOR.js:30:29)
at decodeCredentialPublicKey (webpack-internal:///(rsc)/../../node_modules/.pnpm/@simplewebauthn+server@8.3.5/node_modules/@simplewebauthn/server/esm/helpers/decodeCredentialPublicKey.js:9:108)
at verifySignature (webpack-internal:///(rsc)/../../node_modules/.pnpm/@simplewebauthn+server@8.3.5/node_modules/@simplewebauthn/server/esm/helpers/verifySignature.js:24:113)
at verifyAuthenticationResponse (webpack-internal:///(rsc)/../../node_modules/.pnpm/@simplewebauthn+server@8.3.5/node_modules/@simplewebauthn/server/esm/authentication/verifyAuthenticationResponse.js:166:101)
at async POST (webpack-internal:///(rsc)/./src/app/api/webauthn/verify/route.ts:61:22)
at async C:\Users\vincent\P\c\things\node_modules\.pnpm\next@14.0.3_@babel+core@7.23.3_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:62609 {
incomplete: true,
lastPosition: 1,
values: [ -17 ]
}
Code edited:
const url = new URL(APP_URL);
const respons2 = await verifyAuthenticationResponse({
response: body,
expectedChallenge: challenge,
expectedOrigin: url.origin,
expectedRPID: url.hostname,
authenticator: {
credentialID: Uint8Array.from(
account[0].device_id.split('').map((c) => c.charCodeAt(0)),
),
credentialPublicKey: account[0].public_key,
counter: -1,
},
});
console.log(respons2);
account[0].public_key
is of type Buffer
I'm getting the Unexpected end of CBOR data
too. Tried to follow the docs exactly.
@vincent-thomas and/or @treeder Can you provide an example of your call to verifyAuthenticationResponse()
with the actual values? For the bytes feel free to encode as hex or base64 or whatever, I can decode on my end as I try to understand what's going on. I just need something I can run locally.
@MasterKale here you go (hopefully safe to share this publicly ?):
{
"id": "Z_lauVV2DC6KGN6J3MG1Fw",
"rawId": "Z_lauVV2DC6KGN6J3MG1Fw",
"response": {
"authenticatorData": "xeiCdPuTO2iPRdPJ8QHq119e6SHi0yehQJjkxOXbNdkdAAAAAA",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiWVdKak1USXoiLCJvcmlnaW4iOiJodHRwczovL3JlZmFjdG9yZWQtcGFyYWtlZXQtd3J2cXY2cXdyZnhqdy0zMDAwLmFwcC5naXRodWIuZGV2IiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ",
"signature": "MEQCIAfP3fFC8joFAWP0S7jxiz1fNTeCUeb4zaC6cqd7BGkBAiBOjYz8q-QnOJOTgW_UO2LjQKlkBSnQ7TqeL6o7RS4JXg",
"userHandle": "gsKm2oCU8hgwexAu0pLir"
},
"type": "public-key",
"clientExtensionResults": {},
"authenticatorAttachment": "cross-platform"
}
(hopefully safe to share this publicly ?)
WebAuthn is very sensitive to user privacy, and the nature of public key cryptography means it's generally safe to share public keys, including in cases like this (and in fact I'll need you to share yours because the error being raised here is related to the value you're passing in for authenticator.credentialPublicKey
.)
Ehh, sorry, that wasn't the full input to verifyAuthenticationResponse, here's the full input:
{
"response": {
"id": "Z_lauVV2DC6KGN6J3MG1Fw",
"rawId": "Z_lauVV2DC6KGN6J3MG1Fw",
"response": {
"authenticatorData": "xeiCdPuTO2iPRdPJ8QHq119e6SHi0yehQJjkxOXbNdkdAAAAAA",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiWVdKak1USXoiLCJvcmlnaW4iOiJodHRwczovL3JlZmFjdG9yZWQtcGFyYWtlZXQtd3J2cXY2cXdyZnhqdy0zMDAwLmFwcC5naXRodWIuZGV2IiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ",
"signature": "MEYCIQD69aeXacP_BW7ANxkR-3CfQiPCGBQBtqBebhWdUL0RlQIhAJbz-IfEXQ3MwJL_uzHfsAC1LWv77Maph_Wh3k-Mot-5",
"userHandle": "gsKm2oCU8hgwexAu0pLir"
},
"type": "public-key",
"clientExtensionResults": {},
"authenticatorAttachment": "cross-platform"
},
"expectedChallenge": "YWJjMTIz",
"expectedOrigin": "https://refactored-parakeet-wrvqv6qwrfxjw-3000.app.github.dev",
"expectedRPID": "refactored-parakeet-wrvqv6qwrfxjw-3000.app.github.dev",
"authenticator": {
"credentialID": {
"0": 103,
"1": 249,
"2": 90,
"3": 185,
"4": 85,
"5": 118,
"6": 12,
"7": 46,
"8": 138,
"9": 24,
"10": 222,
"11": 137,
"12": 220,
"13": 193,
"14": 181,
"15": 23
},
"credentialPublicKey": {
"0": 165,
"1": 1,
"2": 2,
"3": 3,
"4": 38,
"5": 32,
"6": 1,
"7": 33,
"8": 88,
"9": 32,
"10": 10,
"11": 177,
"12": 203,
"13": 142,
"14": 138,
"15": 55,
"16": 67,
"17": 217,
"18": 138,
"19": 49,
"20": 25,
"21": 250,
"22": 105,
"23": 203,
"24": 0,
"25": 254,
"26": 120,
"27": 156,
"28": 220,
"29": 85,
"30": 38,
"31": 244,
"32": 43,
"33": 209,
"34": 203,
"35": 119,
"36": 81,
"37": 105,
"38": 3,
"39": 28,
"40": 71,
"41": 226,
"42": 34,
"43": 88,
"44": 32,
"45": 126,
"46": 35,
"47": 124,
"48": 203,
"49": 127,
"50": 54,
"51": 248,
"52": 255,
"53": 76,
"54": 248,
"55": 10,
"56": 80,
"57": 151,
"58": 137,
"59": 47,
"60": 76,
"61": 204,
"62": 92,
"63": 203,
"64": 98,
"65": 130,
"66": 190,
"67": 137,
"68": 144,
"69": 148,
"70": 147,
"71": 254,
"72": 229,
"73": 229,
"74": 170,
"75": 131,
"76": 160
},
"counter": 0,
"credentialDeviceType": "multiDevice",
"credentialBackedUp": true
}
}
Need anything else @MasterKale or is that what you were looking for?
Need anything else @MasterKale or is that what you were looking for?
@treeder That's what I was hoping for. I want to confirm something, though - are the values you're passing in for credentialID
and credentialPublicKey
of type object
? They appear to be, based on the code, but I want to rule out you having passed those Uint8Array
values through JSON.stringify()
before pasting them here as an example.
I did pass the whole object through stringify yes.
On Mon, Dec 18, 2023 at 1:49 PM Matthew Miller @.***> wrote:
Need anything else @MasterKale https://github.com/MasterKale or is that what you were looking for?
@treeder https://github.com/treeder That's what I was hoping for. I want to confirm something, though - are the values you're passing in for credentialID and credentialPublicKey of type object? They appear to be, based on the code, but I want to rule out you having passed those Uint8Array values through JSON.stringify() before pasting them here as an example.
— Reply to this email directly, view it on GitHub https://github.com/MasterKale/SimpleWebAuthn/issues/490#issuecomment-1861323889, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAASQMR2CHM7NRZE6N4EZV3YKCF5DAVCNFSM6AAAAABAE2NQDWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNRRGMZDGOBYHE . You are receiving this because you were mentioned.Message ID: @.***>
Okay, so, if typeof authenticator.credentialID === 'object'
and/or typeof authenticator. credentialPublicKey === 'object'
are true
, then that's your problem here.
Case in point, I ran the code in https://github.com/MasterKale/SimpleWebAuthn/issues/490#issuecomment-1859452074 and it errored out as expected:
console.log(
(await verifyAuthenticationResponse({
'response': {
'id': 'Z_lauVV2DC6KGN6J3MG1Fw',
'rawId': 'Z_lauVV2DC6KGN6J3MG1Fw',
'response': {
'authenticatorData': 'xeiCdPuTO2iPRdPJ8QHq119e6SHi0yehQJjkxOXbNdkdAAAAAA',
'clientDataJSON':
'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiWVdKak1USXoiLCJvcmlnaW4iOiJodHRwczovL3JlZmFjdG9yZWQtcGFyYWtlZXQtd3J2cXY2cXdyZnhqdy0zMDAwLmFwcC5naXRodWIuZGV2IiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ',
'signature':
'MEYCIQD69aeXacP_BW7ANxkR-3CfQiPCGBQBtqBebhWdUL0RlQIhAJbz-IfEXQ3MwJL_uzHfsAC1LWv77Maph_Wh3k-Mot-5',
'userHandle': 'gsKm2oCU8hgwexAu0pLir',
},
'type': 'public-key',
'clientExtensionResults': {},
'authenticatorAttachment': 'cross-platform',
},
'expectedChallenge': 'YWJjMTIz',
'expectedOrigin': 'https://refactored-parakeet-wrvqv6qwrfxjw-3000.app.github.dev',
'expectedRPID': 'refactored-parakeet-wrvqv6qwrfxjw-3000.app.github.dev',
'authenticator': {
'credentialID': { '0': 103, '1': 249, '2': 90, '3': 185, '4': 85, '5': 118, '6': 12, '7': 46, '8': 138, '9': 24, '10': 222, '11': 137, '12': 220, '13': 193, '14': 181, '15': 23 },
'credentialPublicKey': { '0': 165, '1': 1, '2': 2, '3': 3, '4': 38, '5': 32, '6': 1, '7': 33, '8': 88, '9': 32, '10': 10, '11': 177, '12': 203, '13': 142, '14': 138, '15': 55, '16': 67, '17': 217, '18': 138, '19': 49, '20': 25, '21': 250, '22': 105, '23': 203, '24': 0, '25': 254, '26': 120, '27': 156, '28': 220, '29': 85, '30': 38, '31': 244, '32': 43, '33': 209, '34': 203, '35': 119, '36': 81, '37': 105, '38': 3, '39': 28, '40': 71, '41': 226, '42': 34, '43': 88, '44': 32, '45': 126, '46': 35, '47': 124, '48': 203, '49': 127, '50': 54, '51': 248, '52': 255, '53': 76, '54': 248, '55': 10, '56': 80, '57': 151, '58': 137, '59': 47, '60': 76, '61': 204, '62': 92, '63': 203, '64': 98, '65': 130, '66': 190, '67': 137, '68': 144, '69': 148, '70': 147, '71': 254, '72': 229, '73': 229, '74': 170, '75': 131, '76': 160 },
'counter': 0,
},
})).verified,
);
// Uncaught (in promise) Error: Unexpected end of CBOR data
BUT, if I adhere to the API of verifyAuthenticationResponse()
and make sure I'm passing in Uint8Array
for credentialID
and credentialPublicKey
then the response verifies no problem:
console.log(
(await verifyAuthenticationResponse({
'response': {
'id': 'Z_lauVV2DC6KGN6J3MG1Fw',
'rawId': 'Z_lauVV2DC6KGN6J3MG1Fw',
'response': {
'authenticatorData': 'xeiCdPuTO2iPRdPJ8QHq119e6SHi0yehQJjkxOXbNdkdAAAAAA',
'clientDataJSON':
'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiWVdKak1USXoiLCJvcmlnaW4iOiJodHRwczovL3JlZmFjdG9yZWQtcGFyYWtlZXQtd3J2cXY2cXdyZnhqdy0zMDAwLmFwcC5naXRodWIuZGV2IiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ',
'signature':
'MEYCIQD69aeXacP_BW7ANxkR-3CfQiPCGBQBtqBebhWdUL0RlQIhAJbz-IfEXQ3MwJL_uzHfsAC1LWv77Maph_Wh3k-Mot-5',
'userHandle': 'gsKm2oCU8hgwexAu0pLir',
},
'type': 'public-key',
'clientExtensionResults': {},
'authenticatorAttachment': 'cross-platform',
},
'expectedChallenge': 'YWJjMTIz',
'expectedOrigin': 'https://refactored-parakeet-wrvqv6qwrfxjw-3000.app.github.dev',
'expectedRPID': 'refactored-parakeet-wrvqv6qwrfxjw-3000.app.github.dev',
'authenticator': {
// Coercing the `object` into a `Uint8Array`
'credentialID': Uint8Array.from(Object.values({ '0': 103, '1': 249, '2': 90, '3': 185, '4': 85, '5': 118, '6': 12, '7': 46, '8': 138, '9': 24, '10': 222, '11': 137, '12': 220, '13': 193, '14': 181, '15': 23 })),
// Coercing the `object` into a `Uint8Array`
'credentialPublicKey': Uint8Array.from(Object.values({ '0': 165, '1': 1, '2': 2, '3': 3, '4': 38, '5': 32, '6': 1, '7': 33, '8': 88, '9': 32, '10': 10, '11': 177, '12': 203, '13': 142, '14': 138, '15': 55, '16': 67, '17': 217, '18': 138, '19': 49, '20': 25, '21': 250, '22': 105, '23': 203, '24': 0, '25': 254, '26': 120, '27': 156, '28': 220, '29': 85, '30': 38, '31': 244, '32': 43, '33': 209, '34': 203, '35': 119, '36': 81, '37': 105, '38': 3, '39': 28, '40': 71, '41': 226, '42': 34, '43': 88, '44': 32, '45': 126, '46': 35, '47': 124, '48': 203, '49': 127, '50': 54, '51': 248, '52': 255, '53': 76, '54': 248, '55': 10, '56': 80, '57': 151, '58': 137, '59': 47, '60': 76, '61': 204, '62': 92, '63': 203, '64': 98, '65': 130, '66': 190, '67': 137, '68': 144, '69': 148, '70': 147, '71': 254, '72': 229, '73': 229, '74': 170, '75': 131, '76': 160 })),
'counter': 0,
},
})).verified,
// true
);
Ahh, that's helpful. I think I see what I was doing wrong now, I was saving the authenticator in previous steps as a JSON object (stringified) not keeping them as bytes
.
You're solution here fixed it! I added a couple lines like this and it works now:
authenticator.credentialID = Uint8Array.from(Object.values(authenticator.credentialID))
authenticator.credentialPublicKey = Uint8Array.from(Object.values(authenticator.credentialPublicKey))
let vdata = {
response: body.credential,
expectedChallenge: challenge,
expectedOrigin: "https://" + globals.rpId,
expectedRPID: globals.rpId,
authenticator: authenticator,
}
let verification = null
try {
verification = await verifyAuthenticationResponse(vdata);
} catch (error) {
console.error(error);
return c.json({ error: { message: error.message } }, 401)
}
@vincent-thomas I don't know if @treeder had the same issue as you. His problem's solved, if yours is still valid then let me know otherwise I'll close this out.
Describe the issue
Reproduction Steps
On
/api/webauthn/setup
On Client
On
/api/webauthn/verify
Error when
verifyAuthenticationResponse(...)
Expected behavior
Code Samples + WebAuthn Options and Responses
Dependencies
SimpleWebAuthn Libraries