From 5eca3a591667766ff8dd42b67642ce960391004e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20=C3=85berg?= Date: Tue, 1 Jul 2025 21:00:13 +0200 Subject: [PATCH] [PM-18809] Passkey: use ArrayBuffer instead of Uint8Array (#15092) * Passkey: use ArrayBuffer instead of Uint8Array to conform WebAuthn spec * ArrayBufferView generics was too modern for this project * Correctly update the types from Uint8arrays to ArrayBuffers * Fixed broken tests + bugs * Removed arrayBufferViewToArrayBuffer as it's not needed in this invocation paths --------- Co-authored-by: ozraru Co-authored-by: Todd Martin <106564991+trmartin4@users.noreply.github.com> --- .../autofill/services/desktop-autofill.service.ts | 10 +++++----- .../fido2-authenticator.service.abstraction.ts | 10 +++++----- .../services/fido2/credential-id-utils.spec.ts | 4 ++-- .../services/fido2/credential-id-utils.ts | 15 +++++++++------ .../services/fido2/fido2-authenticator.service.ts | 2 +- .../services/fido2/fido2-client.service.ts | 4 ++-- .../src/platform/services/fido2/fido2-utils.ts | 4 ++-- 7 files changed, 26 insertions(+), 23 deletions(-) diff --git a/apps/desktop/src/autofill/services/desktop-autofill.service.ts b/apps/desktop/src/autofill/services/desktop-autofill.service.ts index 7e60c6b8d76..5500bc58f5a 100644 --- a/apps/desktop/src/autofill/services/desktop-autofill.service.ts +++ b/apps/desktop/src/autofill/services/desktop-autofill.service.ts @@ -209,7 +209,7 @@ export class DesktopAutofillService implements OnDestroy { } request.credentialId = Array.from( - parseCredentialId(decrypted.login.fido2Credentials?.[0].credentialId), + new Uint8Array(parseCredentialId(decrypted.login.fido2Credentials?.[0].credentialId)), ); } @@ -336,12 +336,12 @@ export class DesktopAutofillService implements OnDestroy { response: Fido2AuthenticatorGetAssertionResult, ): autofill.PasskeyAssertionResponse { return { - userHandle: Array.from(response.selectedCredential.userHandle), + userHandle: Array.from(new Uint8Array(response.selectedCredential.userHandle)), rpId: request.rpId, - signature: Array.from(response.signature), + signature: Array.from(new Uint8Array(response.signature)), clientDataHash: request.clientDataHash, - authenticatorData: Array.from(response.authenticatorData), - credentialId: Array.from(response.selectedCredential.id), + authenticatorData: Array.from(new Uint8Array(response.authenticatorData)), + credentialId: Array.from(new Uint8Array(response.selectedCredential.id)), }; } diff --git a/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts b/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts index 15655393362..fd3453198e6 100644 --- a/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts +++ b/libs/common/src/platform/abstractions/fido2/fido2-authenticator.service.abstraction.ts @@ -70,7 +70,7 @@ export class Fido2AuthenticatorError extends Error { } export interface PublicKeyCredentialDescriptor { - id: Uint8Array; + id: ArrayBuffer; transports?: ("ble" | "hybrid" | "internal" | "nfc" | "usb")[]; type: "public-key"; } @@ -155,9 +155,9 @@ export interface Fido2AuthenticatorGetAssertionParams { export interface Fido2AuthenticatorGetAssertionResult { selectedCredential: { - id: Uint8Array; - userHandle?: Uint8Array; + id: ArrayBuffer; + userHandle?: ArrayBuffer; }; - authenticatorData: Uint8Array; - signature: Uint8Array; + authenticatorData: ArrayBuffer; + signature: ArrayBuffer; } diff --git a/libs/common/src/platform/services/fido2/credential-id-utils.spec.ts b/libs/common/src/platform/services/fido2/credential-id-utils.spec.ts index 76e068ac01c..1f2217ccd63 100644 --- a/libs/common/src/platform/services/fido2/credential-id-utils.spec.ts +++ b/libs/common/src/platform/services/fido2/credential-id-utils.spec.ts @@ -9,7 +9,7 @@ describe("credential-id-utils", () => { new Uint8Array([ 0x08, 0xd7, 0x0b, 0x74, 0xe9, 0xf5, 0x45, 0x22, 0xa4, 0x25, 0xe5, 0xdc, 0xd4, 0x01, 0x07, 0xe7, - ]), + ]).buffer, ); }); @@ -20,7 +20,7 @@ describe("credential-id-utils", () => { new Uint8Array([ 0x08, 0xd7, 0x0b, 0x74, 0xe9, 0xf5, 0x45, 0x22, 0xa4, 0x25, 0xe5, 0xdc, 0xd4, 0x01, 0x07, 0xe7, - ]), + ]).buffer, ); }); diff --git a/libs/common/src/platform/services/fido2/credential-id-utils.ts b/libs/common/src/platform/services/fido2/credential-id-utils.ts index 685669f0da3..08ea33114f5 100644 --- a/libs/common/src/platform/services/fido2/credential-id-utils.ts +++ b/libs/common/src/platform/services/fido2/credential-id-utils.ts @@ -3,13 +3,13 @@ import { Fido2Utils } from "./fido2-utils"; import { guidToRawFormat } from "./guid-utils"; -export function parseCredentialId(encodedCredentialId: string): Uint8Array { +export function parseCredentialId(encodedCredentialId: string): ArrayBuffer { try { if (encodedCredentialId.startsWith("b64.")) { return Fido2Utils.stringToBuffer(encodedCredentialId.slice(4)); } - return guidToRawFormat(encodedCredentialId); + return guidToRawFormat(encodedCredentialId).buffer; } catch { return undefined; } @@ -18,13 +18,16 @@ export function parseCredentialId(encodedCredentialId: string): Uint8Array { /** * Compares two credential IDs for equality. */ -export function compareCredentialIds(a: Uint8Array, b: Uint8Array): boolean { - if (a.length !== b.length) { +export function compareCredentialIds(a: ArrayBuffer, b: ArrayBuffer): boolean { + if (a.byteLength !== b.byteLength) { return false; } - for (let i = 0; i < a.length; i++) { - if (a[i] !== b[i]) { + const viewA = new Uint8Array(a); + const viewB = new Uint8Array(b); + + for (let i = 0; i < viewA.length; i++) { + if (viewA[i] !== viewB[i]) { return false; } } diff --git a/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts b/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts index bac1b218657..e560a77cc2e 100644 --- a/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts +++ b/libs/common/src/platform/services/fido2/fido2-authenticator.service.ts @@ -514,7 +514,7 @@ async function getPrivateKeyFromFido2Credential( const keyBuffer = Fido2Utils.stringToBuffer(fido2Credential.keyValue); return await crypto.subtle.importKey( "pkcs8", - keyBuffer, + new Uint8Array(keyBuffer), { name: fido2Credential.keyAlgorithm, namedCurve: fido2Credential.keyCurve, diff --git a/libs/common/src/platform/services/fido2/fido2-client.service.ts b/libs/common/src/platform/services/fido2/fido2-client.service.ts index 5d5f2a879cb..431585441a7 100644 --- a/libs/common/src/platform/services/fido2/fido2-client.service.ts +++ b/libs/common/src/platform/services/fido2/fido2-client.service.ts @@ -127,9 +127,9 @@ export class Fido2ClientService } const userId = Fido2Utils.stringToBuffer(params.user.id); - if (userId.length < 1 || userId.length > 64) { + if (userId.byteLength < 1 || userId.byteLength > 64) { this.logService?.warning( - `[Fido2Client] Invalid 'user.id' length: ${params.user.id} (${userId.length})`, + `[Fido2Client] Invalid 'user.id' length: ${params.user.id} (${userId.byteLength})`, ); throw new TypeError("Invalid 'user.id' length"); } diff --git a/libs/common/src/platform/services/fido2/fido2-utils.ts b/libs/common/src/platform/services/fido2/fido2-utils.ts index 6413eeade04..99e260f4a53 100644 --- a/libs/common/src/platform/services/fido2/fido2-utils.ts +++ b/libs/common/src/platform/services/fido2/fido2-utils.ts @@ -47,8 +47,8 @@ export class Fido2Utils { .replace(/=/g, ""); } - static stringToBuffer(str: string): Uint8Array { - return Fido2Utils.fromB64ToArray(Fido2Utils.fromUrlB64ToB64(str)); + static stringToBuffer(str: string): ArrayBuffer { + return Fido2Utils.fromB64ToArray(Fido2Utils.fromUrlB64ToB64(str)).buffer; } static bufferSourceToUint8Array(bufferSource: BufferSource): Uint8Array {