Skip to content

Commit

Permalink
Merge pull request #521 from MasterKale/fix/513-cbor-x-type-issues
Browse files Browse the repository at this point in the history
fix/513-cbor-x-type-issues
  • Loading branch information
MasterKale authored Feb 16, 2024
2 parents 768f7d1 + 2953163 commit 0d7ebc2
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 31 deletions.
9 changes: 4 additions & 5 deletions packages/server/build_npm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,6 @@ await build({
name: '@hexagon/base64',
version: '^1.1.27',
},
'https://deno.land/x/[email protected]/index.js': {
name: 'cbor-x',
subPath: 'index-no-eval',
version: '^1.5.2',
},
'https://esm.sh/[email protected]': {
name: 'cross-fetch',
version: '^4.0.0',
Expand All @@ -99,6 +94,10 @@ await build({
name: '@peculiar/asn1-android',
version: '^2.3.10',
},
'https://deno.land/x/[email protected]/index.ts': {
name: '@levischuck/tiny-cbor',
version: '^0.2.2',
},
// Mapping for '../../types/src/index.ts' in deps.ts
'../types/src/index.ts': {
name: '@simplewebauthn/types',
Expand Down
6 changes: 3 additions & 3 deletions packages/server/deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/server/src/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export type {
UserVerificationRequirement,
} from '../../types/src/index.ts';

// cbor (a.k.a. cbor-x in Node land)
export * as cborx from 'https://deno.land/x/[email protected].2/index.js';
// tiny_cbor (a.k.a. tiny-cbor in Node land)
export * as tinyCbor from 'https://deno.land/x/[email protected].2/index.ts';

// b64 (a.k.a. @hexagon/base64 in Node land)
export { default as base64 } from 'https://deno.land/x/[email protected]/src/base64.js';
Expand Down
24 changes: 5 additions & 19 deletions packages/server/src/helpers/iso/isoCBOR.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { cborx } from '../../deps.ts';
import { tinyCbor } from '../../deps.ts';

/**
* This encoder should keep CBOR data the same length when data is re-encoded
* Whatever CBOR encoder is used should keep CBOR data the same length when data is re-encoded
*
* MOST CRITICALLY, this means the following needs to be true of whatever CBOR library we use:
* - CBOR Map type values MUST decode to JavaScript Maps
Expand All @@ -10,10 +10,6 @@ import { cborx } from '../../deps.ts';
* So long as these requirements are maintained, then CBOR sequences can be encoded and decoded
* freely while maintaining their lengths for the most accurate pointer movement across them.
*/
const encoder = new cborx.Encoder({
mapsAsObjects: false,
tagUint8Array: false,
});

/**
* Decode and return the first item in a sequence of CBOR-encoded values
Expand All @@ -25,18 +21,8 @@ const encoder = new cborx.Encoder({
export function decodeFirst<Type>(input: Uint8Array): Type {
// Make a copy so we don't mutate the original
const _input = new Uint8Array(input);
const decoded = encoder.decodeMultiple(_input) as undefined | Type[];
const decoded = tinyCbor.decodePartialCBOR(_input, 0) as [Type, number];

if (decoded === undefined) {
throw new Error('CBOR input data was empty');
}

/**
* Typing on `decoded` is `void | []` which causes TypeScript to think that it's an empty array,
* and thus you can't destructure it. I'm ignoring that because the code works fine in JS, and
* so this should be a valid operation.
*/
// @ts-ignore 2493
const [first] = decoded;

return first;
Expand All @@ -45,6 +31,6 @@ export function decodeFirst<Type>(input: Uint8Array): Type {
/**
* Encode data to CBOR
*/
export function encode(input: unknown): Uint8Array {
return encoder.encode(input);
export function encode(input: tinyCbor.CBORType): Uint8Array {
return tinyCbor.encodeCBOR(input);
}
19 changes: 17 additions & 2 deletions packages/server/src/helpers/parseAuthenticatorData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,17 @@ export function parseAuthenticatorData(
const firstDecoded = isoCBOR.decodeFirst<COSEPublicKey>(
authData.slice(pointer),
);
const firstEncoded = Uint8Array.from(isoCBOR.encode(firstDecoded));
const firstEncoded = Uint8Array.from(
/**
* Casting to `Map` via `as unknown` here because TS doesn't make it possible to define Maps
* with discrete keys and properties with known types per pair, and CBOR libs typically parse
* CBOR Major Type 5 to `Map` because you can have numbers for keys. A `COSEPublicKey` can be
* generalized as "a Map with numbers for keys and either numbers or bytes for values" though.
* If this presumption falls apart then other parts of verification later on will fail so we
* should be safe doing this here.
*/
isoCBOR.encode(firstDecoded as unknown as Map<number, number | Uint8Array>),
);

if (foundBadCBOR) {
// Restore the bit we changed so that `authData` is the same as it came in and won't break
Expand All @@ -92,7 +102,12 @@ export function parseAuthenticatorData(
let extensionsDataBuffer: Uint8Array | undefined = undefined;

if (flags.ed) {
const firstDecoded = isoCBOR.decodeFirst(authData.slice(pointer));
/**
* Typing here feels a little sloppy but we're immediately CBOR-encoding this back to bytes to
* more diligently parse via `decodeAuthenticatorExtensions()` so :shrug:
*/
type AuthenticatorExtensionData = Map<string, Uint8Array>;
const firstDecoded = isoCBOR.decodeFirst<AuthenticatorExtensionData>(authData.slice(pointer));
extensionsDataBuffer = Uint8Array.from(isoCBOR.encode(firstDecoded));
extensionsData = decodeAuthenticatorExtensions(extensionsDataBuffer);
pointer += extensionsDataBuffer.byteLength;
Expand Down

0 comments on commit 0d7ebc2

Please sign in to comment.