summaryrefslogtreecommitdiffhomepage
path: root/packages/server/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/server/src')
-rw-r--r--packages/server/src/helpers/parseAuthenticatorData.test.ts20
-rw-r--r--packages/server/src/helpers/parseAuthenticatorData.ts17
2 files changed, 36 insertions, 1 deletions
diff --git a/packages/server/src/helpers/parseAuthenticatorData.test.ts b/packages/server/src/helpers/parseAuthenticatorData.test.ts
index 0e4b112..e1f5be2 100644
--- a/packages/server/src/helpers/parseAuthenticatorData.test.ts
+++ b/packages/server/src/helpers/parseAuthenticatorData.test.ts
@@ -2,7 +2,7 @@ import { assertEquals } from 'https://deno.land/std@0.198.0/assert/mod.ts';
import { parseAuthenticatorData } from './parseAuthenticatorData.ts';
import { AuthenticationExtensionsAuthenticatorOutputs } from './decodeAuthenticatorExtensions.ts';
-import { isoBase64URL } from './iso/index.ts';
+import { isoBase64URL, isoUint8Array } from './iso/index.ts';
// Grabbed this from a Conformance test, contains attestation data
const authDataWithAT = isoBase64URL.toBuffer(
@@ -64,3 +64,21 @@ Deno.test('should parse extension data', () => {
} as AuthenticationExtensionsAuthenticatorOutputs,
);
});
+
+Deno.test('should parse malformed authenticator data from Firefox 117', () => {
+ /**
+ * Firefox 117 is incorrectly serializing authenticator data, and using string values for kty and
+ * crv at the same time. See the following issues for more context (I've dealt with this issue
+ * before, over in the py_webauthn project):
+ *
+ * - https://github.com/duo-labs/py_webauthn/issues/175
+ * - https://github.com/mozilla/authenticator-rs/pull/292
+ */
+ const authDataBadKty =
+ 'b40499b0271a68957267de4ec40056a74c8758c6582e1e01fcf357d73101e7ba450000000400000000000000000000000000000000008072d3a1a3fa7cf32f44367df847585ff0850c7bd62c338ab45be1fda6fdb79982f96c20efc0bb6ed9347e8c1e77690e67b225b485a098f6f46fde3f2a85acd0177a04d6bb5c7566fb89881dfe48ea7abc361f7acaf86a5966adef557930fa5c045c636f50cf938e508a81b845134eb2988dc3af0ab6f98cfc615532684b4a6363a301634f4b50032720674564323535313921982018d51858187318e6188918eb18ab187e18fd18fd185d184b08184b187318e818e118f818c71518ff18f5183a18fd18a3186b185f1109183e183b14';
+
+ const parsed = parseAuthenticatorData(isoUint8Array.fromHex(authDataBadKty));
+
+ // If we can assert this then it means we could parse the bad auth data above
+ assertEquals(parsed.flags.at, true);
+});
diff --git a/packages/server/src/helpers/parseAuthenticatorData.ts b/packages/server/src/helpers/parseAuthenticatorData.ts
index 497f2d4..28bd469 100644
--- a/packages/server/src/helpers/parseAuthenticatorData.ts
+++ b/packages/server/src/helpers/parseAuthenticatorData.ts
@@ -53,6 +53,23 @@ export function parseAuthenticatorData(
credentialID = authData.slice(pointer, pointer += credIDLen);
+ /**
+ * Firefox 117 incorrectly CBOR-encodes authData when EdDSA (-8) is used for the public key.
+ * A CBOR "Map of 3 items" (0xa3) should be "Map of 4 items" (0xa4), and if we manually adjust
+ * the single byte there's a good chance the authData can be correctly parsed.
+ *
+ * This browser release also incorrectly uses the string labels "OKP" and "Ed25519" instead of
+ * their integer representations for kty and crv respectively. That's why the COSE public key
+ * in the hex below looks so odd.
+ */
+ // Bytes decode to `{ 1: "OKP", 3: -8, -1: "Ed25519" }` (it's missing key -2 a.k.a. COSEKEYS.x)
+ const badEdDSACBOR = isoUint8Array.fromHex('a301634f4b500327206745643235353139');
+ const bytesAtCurrentPosition = authData.slice(pointer, pointer + badEdDSACBOR.byteLength);
+ if (isoUint8Array.areEqual(badEdDSACBOR, bytesAtCurrentPosition)) {
+ // Change the bad CBOR 0xa3 to 0xa4 so that the credential public key can be recognized
+ authData[pointer] = 0xa4;
+ }
+
// Decode the next CBOR item in the buffer, then re-encode it back to a Buffer
const firstDecoded = isoCBOR.decodeFirst<COSEPublicKey>(
authData.slice(pointer),