diff options
Diffstat (limited to 'packages/server')
-rw-r--r-- | packages/server/deno.lock | 37 | ||||
-rw-r--r-- | packages/server/src/helpers/parseAuthenticatorData.test.ts | 20 | ||||
-rw-r--r-- | packages/server/src/helpers/parseAuthenticatorData.ts | 17 |
3 files changed, 53 insertions, 21 deletions
diff --git a/packages/server/deno.lock b/packages/server/deno.lock index ea6ba9c..eb4e600 100644 --- a/packages/server/deno.lock +++ b/packages/server/deno.lock @@ -137,26 +137,23 @@ "https://deno.land/x/wasmbuild@0.14.1/cache.ts": "89eea5f3ce6035a1164b3e655c95f21300498920575ade23161421f5b01967f4", "https://deno.land/x/wasmbuild@0.14.1/loader.ts": "d98d195a715f823151cbc8baa3f32127337628379a02d9eb2a3c5902dbccfc02", "https://deno.land/x/xhr@0.3.0/mod.ts": "094aacd627fd9635cd942053bf8032b5223b909858fa9dc8ffa583752ff63b20", - "https://esm.sh/@peculiar/asn1-android@2.3.6": "ad561af8e9c98ca24edea2a06b78126388d30e8d7563aa8ff019539e63ad1409", - "https://esm.sh/@peculiar/asn1-ecc@2.3.6": "09b28e664b009f8682fbbc6bfaae9c6738ede103cc7eb2250304687fc611cb45", - "https://esm.sh/@peculiar/asn1-rsa@2.3.6": "28c4bbbc2cdde75e0899a0a97b1d332be7f60c1b096c43749cc9f02b248be025", - "https://esm.sh/@peculiar/asn1-schema@2.3.6": "c19e745f7409b7f09be724c8b6a9e58b0399f5c58d86290a1a44bac2285991d5", - "https://esm.sh/@peculiar/asn1-x509@2.3.6": "38b5e7aa6ba5da5c13cc20550d35bbe8190738b34436faf4c2f3b1f81588a4ca", - "https://esm.sh/cross-fetch@4.0.0": "c7c8c2e11976c1815ac47c08e8195a674513c4b82df0dcc296e759ceaf8f8c21", - "https://esm.sh/debug@4.3.4": "c6bcd0430fb5d0a499bbacce8bbe8f051616cda3c0696337b0749247e451f0db", - "https://esm.sh/v131/@peculiar/asn1-android@2.3.6/denonext/asn1-android.mjs": "34764b794e10675a2567bbe7bdc7fde073353e8abc413fbcd9c3fde2ed1c5c3b", - "https://esm.sh/v131/@peculiar/asn1-ecc@2.3.6/denonext/asn1-ecc.mjs": "be8ea819764a103e2ba44c38764079d760a1568fbb54b26bc402d2ce471a8ff7", - "https://esm.sh/v131/@peculiar/asn1-rsa@2.3.6/denonext/asn1-rsa.mjs": "728598dab7aa294feb67304a87d21e854050b29f72c7230f45fd798b1fcf8e86", - "https://esm.sh/v131/@peculiar/asn1-schema@2.3.6/denonext/asn1-schema.mjs": "04aed5d13f20547dae79896a6d50797e08fe3c6b1de529f756f48a6da591a66e", - "https://esm.sh/v131/@peculiar/asn1-x509@2.3.6/denonext/asn1-x509.mjs": "fb3dc85d465d8b7594ba9ae91c109143e330af6c2ef814d3d112ab7d63417450", - "https://esm.sh/v131/asn1js@3.0.5/denonext/asn1js.mjs": "c430a2ca4adfbb1d38611c8d3b1c040aefa7d9bafd7d15f552667026427a88b7", - "https://esm.sh/v131/cross-fetch@4.0.0/denonext/cross-fetch.mjs": "238eae32034ab217cdbef10b812c7357f61ab2730c58207f4cf9135e9dec7a61", - "https://esm.sh/v131/debug@4.3.4/denonext/debug.mjs": "892826bb4505deb6337df2f0f72b1e355e5377e702dd739b78774539d7482f5c", - "https://esm.sh/v131/ipaddr.js@2.1.0/denonext/ipaddr.mjs": "214c1ee845e73e7c51ba673b36e7e6b9c5d8e8fb1fc19443444ad9cec44adf7e", - "https://esm.sh/v131/ms@2.1.2/denonext/ms.mjs": "aa4dc45ba72554c5011168f8910cc646c37af53cfff1a15a4decced838b8eb14", - "https://esm.sh/v131/pvtsutils@1.3.2/denonext/pvtsutils.mjs": "1018ae12b1c67a8a314a265834bf3a7252c2105611a6699f215b543ee7f006b0", - "https://esm.sh/v131/pvutils@1.1.3/denonext/pvutils.mjs": "ad156a239ec0f1aa99f123fab44abc292c87d4fd6969d7af264436630457523c", - "https://esm.sh/v131/tslib@2.6.1/denonext/tslib.mjs": "4694ecbc32a05aa4a37497b65f3e55018c24b2a4e4f05462a7746fc4850b4791" + "https://esm.sh/@peculiar/asn1-android@2.3.6": "fb4dd2b9fe423ad0f98c5f7c8b365404f56827b3cfc1b9abbce6d419f72908c3", + "https://esm.sh/@peculiar/asn1-ecc@2.3.6": "6e259ae1390d9d6f0bb3055b4d06b467925747f8db9f78156c34a5ea79beaac1", + "https://esm.sh/@peculiar/asn1-rsa@2.3.6": "9c2a9481c9515ea860378742ad255bce7424a0d2f24f87e7d390aac669135dc8", + "https://esm.sh/@peculiar/asn1-schema@2.3.6": "c15028356c71536e543f9112a04efc56aa9b47d739e1d57d162fe1a6e5abc6ce", + "https://esm.sh/@peculiar/asn1-x509@2.3.6": "701eadefdaac96a504cb024efb38dec25c1fa2c61b3963b2b6d17c324fcc54e5", + "https://esm.sh/cross-fetch@4.0.0": "455ae44f37acd1ed33e9449c428750b6129152532aeccd3de69bd19005a38331", + "https://esm.sh/v132/@peculiar/asn1-android@2.3.6/denonext/asn1-android.mjs": "5e01acec4a325066184c8a2f2f8d4864a571b9039b5679078b3893a93e90a1b5", + "https://esm.sh/v132/@peculiar/asn1-ecc@2.3.6/denonext/asn1-ecc.mjs": "5989ad7184187eb1b16e2133deecf1d2b96c31ef96927b1892b2c2653890cb69", + "https://esm.sh/v132/@peculiar/asn1-rsa@2.3.6/denonext/asn1-rsa.mjs": "f687c324c0d89aa12e450a2b33aaf7271bb77e05e2fef9a83544a94ecb7f8c5b", + "https://esm.sh/v132/@peculiar/asn1-schema@2.3.6/denonext/asn1-schema.mjs": "f4cc2f4f847fff6b9789e13efee1e8c4a3d3f67c16caa90d532619b67ea46241", + "https://esm.sh/v132/@peculiar/asn1-x509@2.3.6/denonext/asn1-x509.mjs": "34745efad09645b27c6c3125aca6b91c3478f2f417eff74d43d5bf5fb412e5bf", + "https://esm.sh/v132/asn1js@3.0.5/denonext/asn1js.mjs": "06e1a6a2bbe1ab615ab45fa4c5351749fb47a24bd8a9b72f490df8bd17f30cb3", + "https://esm.sh/v132/cross-fetch@4.0.0/denonext/cross-fetch.mjs": "238eae32034ab217cdbef10b812c7357f61ab2730c58207f4cf9135e9dec7a61", + "https://esm.sh/v132/ipaddr.js@2.1.0/denonext/ipaddr.mjs": "214c1ee845e73e7c51ba673b36e7e6b9c5d8e8fb1fc19443444ad9cec44adf7e", + "https://esm.sh/v132/pvtsutils@1.3.5/denonext/pvtsutils.mjs": "016782b990e2652a326cf1d8984c2adc4552171da902cc73dc8e12ffdbe3a100", + "https://esm.sh/v132/pvutils@1.1.3/denonext/pvutils.mjs": "ad156a239ec0f1aa99f123fab44abc292c87d4fd6969d7af264436630457523c", + "https://esm.sh/v132/tslib@2.6.2/denonext/tslib.mjs": "29782bcd3139f77ec063dc5a9385c0fff4a8d0a23b6765c73d9edeb169a04bf1" }, "npm": { "specifiers": { 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), |