I’m trying to validate the signature received from an assertion request but fail. Here are the objects I’ve receiving from the client, the assertion and attestation, respectively:
const attestationChallenge = 'p58vEOB1TJ0Rh3PSwyTKnujxmYYQmGka20bYBK8hw8sfL/2btBbNeSmIiycTsvFfEgGzp7X5JVkpW4FMer6mcT5DOcgfh10OGXUdFe51exz/mOuj7+TRIxQNcaJ0jv/QTT9kCvTRydo2ntP2gsf2oVnVH+nweTEG4iY9GNFwDcU=';
const attestation = {
id: 'XT39NMONrxoh29HHmyh35qwaS1o=',
rawId: 'XT39NMONrxoh29HHmyh35qwaS1o=',
response: {
clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoicDU4dkVPQjFUSjBSaDNQU3d5VEtudWp4bVlZUW1Ha2EyMGJZQks4aHc4c2ZMXzJidEJiTmVTbUlpeWNUc3ZGZkVnR3pwN1g1SlZrcFc0Rk1lcjZtY1Q1RE9jZ2ZoMTBPR1hVZEZlNTFleHpfbU91ajctVFJJeFFOY2FKMGp2X1FUVDlrQ3ZUUnlkbzJudFAyZ3NmMm9WblZILW53ZVRFRzRpWTlHTkZ3RGNVIiwib3JpZ2luIjoiaHR0cHM6Ly90bXB0ZXN0NTU1LmJsb2Nrc29mdGxhYi5jb20ifQ==',
attestationObject: 'o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViY85atP17k4jCSodKGG3KumgFtv9mzmvanMjekolX24mVdAAAAAPv8MAcVTk7MjAtuAgVX170AFF09/TTDja8aIdvRx5sod+asGktapQECAyYgASFYIHSvWI6jrp0v03xk2GzDDnMFD3hkZ+Vu4IFvXLPBNUDLIlgg8E4TIs8fiErLT7nEeOI6gjb+zTsKSQjPi6bplGD4djA='
}
};
const assertionChallenge = 'ECJ3xtuY4U71MEZyjRa8pKcFBPXkRORXkzNe43P-OpdITVirSPjpn9aTzfFUOM0Gd9yR-KI82RRkK0_nei-2zy0HXVSDvfQXwLsIZmXBY7uuwSEaDEB5G57fc3B3Uu1bv8tjLSsdpzp5BNSi5kWNIcImwTVmAyeeNXuKp8ZPhbs';
const assertion = {
id: 'ibYKqMzdLS3eEYNZKzoYBuPHNlY=',
rawId: 'ibYKqMzdLS3eEYNZKzoYBuPHNlY=',
response: {
clientDataJSON: 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiRUNKM3h0dVk0VTcxTUVaeWpSYThwS2NGQlBYa1JPUlhrek5lNDNQLU9wZElUVmlyU1BqcG45YVR6ZkZVT00wR2Q5eVItS0k4MlJSa0swX25laS0yenkwSFhWU0R2ZlFYd0xzSVptWEJZN3V1d1NFYURFQjVHNTdmYzNCM1V1MWJ2OHRqTFNzZHB6cDVCTlNpNWtXTkljSW13VFZtQXllZU5YdUtwOFpQaGJzIiwib3JpZ2luIjoiaHR0cHM6Ly90bXB0ZXN0NTU1LmJsb2Nrc29mdGxhYi5jb20ifQ==',
authenticatorData: '85atP17k4jCSodKGG3KumgFtv9mzmvanMjekolX24mUdAAAAAA==',
signature: 'MEUCIQCAJrsIKKXp7Fmw8jVzxH5eLVTZqSpx0OihDtGCbZ5/ywIgYH48xfQlAA6+lY0NjWsHa7+vwEzmGwEOU132zwAOYTo=',
userHandle: 'SmU2Qm9NaDM3dW5sQVFUNU5FVGllZw=='
}
};
Here’s the decoded JWK of the public key:
{
"kty": "EC",
"alg": "ES256",
"crv": "P-256",
"x": "dK9YjqOunS/TfGTYbMMOcwUPeGRn5W7ggW9cs8E1QMs=",
"y": "8E4TIs8fiErLT7nEeOI6gjb+zTsKSQjPi6bplGD4djA="
}
I’ve also noticed a pattern in the signatures: they all seem to begin with a very similar structure, usually it begins with ME and contains characters such as U, I, C and Q shortly after, but not as consistently as ME. This leads me to believe the signature begins with some stable hash of the authenticator data, as written per in spec, however, it only applies to Apple attestation format, but the format returned from the attestation request is none and trying to concatenate the challenge and the authenticator data doesn’t seem to make the verification work.
Here’s what I’ve tried:
const authData = Buffer.from(assertion.response.authenticatorData, 'base64');
const { createHash, verify } = require('crypto');
const hash = createHash('sha256').update(Buffer.from(attestation.response.clientDataJSON, 'base64')).digest();
const concat = Buffer.concat([authData, hash]);
const result = verify(
null,
concat,
{ key, format: 'jwk' }, // the JWK above
Buffer.from(assertion.response.signature, 'base64')
);
console.log(result);
Constantine is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.