decoding webauthn

This commit is contained in:
Dusan Jakub
2023-10-11 23:08:58 +02:00
parent d77317adab
commit 830048d3e2
2 changed files with 69 additions and 1 deletions

View File

@@ -221,6 +221,7 @@
};
WebAuthn.base64ToBuffer = base64ToBuffer;
WebAuthn.bufferToBase64 = bufferToBase64;
return WebAuthn;
}));

View File

@@ -239,6 +239,8 @@
This is a base64 encoded binary representation of an attestation statement. The attestation statement is produced by the authenticator to prove to the relying party (e.g., a website) that a new public key credential has been created in the authenticator. It typically contains details about the authenticator, a freshly generated public key for the user, some metadata, and a signature from the authenticator. It is <a href="https://cbor.io/">CBOR</a> encoded.
</p>
<div class="code" id="navigator-attestationObject" style="height: 150px; overflow-y: scroll;"></div>
<p class="button-label">The authData is <a href="https://www.w3.org/TR/webauthn-2/#sctn-attested-credential-data">binary encoded</a> and contain the actual public key, but also more flags and info about the authentication:</p>
<div class="code" id="navigator-authData"></div>
</li>
<li class="collection-item">
<p class="emphasis"><b>clientDataJSON</b></p>
@@ -345,6 +347,8 @@
<p>
This contains information about the authentication event. It typically includes the hash of the <b>clientDataJSON</b>, a sign count (to protect against clone attacks), and other data relevant to the authentication process.
</p>
<p class="button-label">It is <a href="https://www.w3.org/TR/webauthn-2/#sctn-attested-credential-data">binary encoded</a> and this time does not contain the public key:</p>
<div class="code" id="navigator-authenticatorData"></div>
</li>
<li class="collection-item">
<p class="emphasis"><b>signature</b></p>
@@ -418,6 +422,63 @@
}
}
function readHexString(view, start, len){
const hash = new Uint8Array(len);
for (let i = 0; i < len; i++) {
hash[i] = view.getUint8(i+start);
}
return Array.from(hash).map(byte => {
return ('0' + byte.toString(16)).slice(-2); // Ensure two-digit hex representation
}).join('');
}
function parseCredentialPubKey(array) {
console.log(array)
let view = new DataView(array.buffer, array.byteOffset, array.byteLength);
let credentialIdLength = view.getUint16(16, false);
return {
"aaguid": readHexString(view, 0, 16),
"credentialIdLength": credentialIdLength,
"credentialId": WebAuthn.bufferToBase64(array.slice(18, credentialIdLength).buffer),
"credentialPublicKey": WebAuthn.bufferToBase64(array.slice(18+credentialIdLength).buffer)
}
}
function parseAuthenticatorData(array) {
try {
console.log(array)
let view = new DataView(array.buffer, array.byteOffset, array.byteLength);
let flags = view.getInt8(32);
const hashHex = readHexString(view, 0, 32);
const result = {
"rpIdHash": hashHex,
"flags": {
"userPresent": !!(flags & 1),
"userVerified": !!(flags & (1 << 2)),
"attestedCredentialData": !!(flags & (1 << 6)),
"extensionDataIncluded": !!(flags & (1 << 7))
},
"signCount": view.getUint32(33, false),
}
try {
if (result.flags.attestedCredentialData) {
result['credentialPubKey'] = parseCredentialPubKey(array.slice(37));
}
} catch (e) {
console.log(e)
}
return result;
} catch (e) {
console.warn(e)
return "Unable to parse: " + e;
}
}
function tracer(stage, params) {
console.log(stage, params)
@@ -498,7 +559,10 @@
$("#navigator-attestation").showInViewport();
$("#navigator-attestation-body").html(JSON.stringify(response, null, 2));
$("#navigator-attestation-clientDataJSON").html(JSON.stringify(JSON.parse(tryDecodeBase64(response.response.clientDataJSON)), null, 2));
$("#navigator-attestationObject").html(JSON.stringify(CBOR.decode(WebAuthn.base64ToBuffer(response.response.attestationObject)), null, 2));
let attestationObject = CBOR.decode(WebAuthn.base64ToBuffer(response.response.attestationObject));
let authData = parseAuthenticatorData(attestationObject.authData);
$("#navigator-attestationObject").html(JSON.stringify(attestationObject, null, 2));
$("#navigator-authData").html(JSON.stringify(authData, null, 2));
return continueButton("#navigator-attestation", response);
}
@@ -512,6 +576,9 @@
$("#navigator-assertion").showInViewport();
$("#navigator-assertion-body").html(JSON.stringify(response, null, 2));
$("#navigator-assertion-clientDataJSON").html(JSON.stringify(JSON.parse(tryDecodeBase64(response.response.clientDataJSON)), null, 2));
let authenticatorData = WebAuthn.base64ToBuffer(response.response.authenticatorData);
let authData = parseAuthenticatorData(new Uint8Array(authenticatorData));
$("#navigator-authenticatorData").html(JSON.stringify(authData, null, 2));
return continueButton("#navigator-assertion", response);
}