Reputation: 7742
I have followed this tutorial https://webauthn.guide/#registration
I am working with a yubico nfc key and I nearly managed to enroll the security key. I send a random byte challenge from the server to enroll the key, and other data.
When I register the key I managed to decode the clientDataJson and the authentication response to retrieve a lot of information. However I cannot figure out what to do with the credentialId et authData buffers, I tried decoding them, decrypt them but I always got somme strange data and nothing that looks like a credentialId or a public key.
Here is the code I got so far
var createCredentialDefaultArgs = {
publicKey: {
// Relying Party (a.k.a. - Service):
rp: {
name: 'Dummy'
},
// User:
user: {
id: new Uint8Array(16),
name: 'John Doe',
displayName: 'Mr Doe'
},
pubKeyCredParams: [{
type: "public-key",
alg: -7
}],
attestation: "direct",
timeout: 60000,
challenge: new Uint8Array(/* stuff*/).buffer
}
};
$('[data-register-webauthn]')
.on('click', function () {
// register / create a new credential
navigator.credentials.create(createCredentialDefaultArgs)
.then((cred) => {
console.log("NEW CREDENTIAL", cred);
const utf8Decoder = new TextDecoder('utf-8');
const decodedClientData = utf8Decoder.decode(cred.response.clientDataJSON);
// parse the string as an object
const clientDataObj = JSON.parse(decodedClientData);
const decodedAttestationObj = CBOR.decode(cred.response.attestationObject);
const {authData} = decodedAttestationObj;
// get the length of the credential ID
const dataView = new DataView(new ArrayBuffer(2));
const idLenBytes = authData.slice(53, 55);
idLenBytes.forEach(
(value, index) => dataView.setUint8(
index, value)
);
const credentialIdLength = dataView.getUint16();
// get the credential ID
const credentialId = authData.slice(
55, credentialIdLength);
// get the public key object
const publicKeyBytes = authData.slice(
55 + credentialIdLength);
// the publicKeyBytes are encoded again as CBOR
const publicKeyObject = CBOR.decode(
publicKeyBytes.buffer);
console.log(publicKeyObject)
})
.catch((err) => {
console.log("ERROR", err);
});
})
In the end, I don't know what to do with the public key object and the credentialId. Deconding seems useless.
Any idea ?
Upvotes: 4
Views: 4288
Reputation: 7073
I always got some strange data and nothing that looks like a credentialId or a public key.
That's because both are byte sequences.
The credentialId
you parsed from authData
is a string of random bytes (usually 96 bytes long) generated by the U2F key, so don't expect those to make sense.
The publicKey
variable is a bit more tricky as it is CBOR-encoded (not your regular PEM string), which after decoding it in publicKeyObject
should give you an output like this:
{
1: 2, // Ellipic Curve key type
3: -7, // ES256 signature algorithm
-1: 1, // P-256 curve
-2: 0x7885DB484..., // X value
-3: 0x814F3DD31... // Y value
}
In the end, I don't know what to do with the public key object and the credentialId.
You need the Credential ID to identify the user who is trying to authenticate against your website and the Public Key to verify its identity.
All the other information extracted from the authData
response should be validated but there's no need to keep it, just save the pair credentialId
and publicKeyBytes
.
This websites explains the authentication process in fair detail: https://webauthn.guide/#authentication
To find out how to validate the signature check this link: https://w3c.github.io/webauthn/#fig-signature
Upvotes: 8
Reputation: 5021
Credential ID and Credential Public Key values are both non human palatable byte-strings.
Regarding what to do with them. You store them next to the user data in your database or any other long term storage your server is using, so you can then use them as inputs for future Authentications ceremonies.
Upvotes: 1