1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

[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 <ozraru@raru.work>
Co-authored-by: Todd Martin <106564991+trmartin4@users.noreply.github.com>
This commit is contained in:
Anders Åberg
2025-07-01 21:00:13 +02:00
committed by GitHub
parent c9aa8498c7
commit 5eca3a5916
7 changed files with 26 additions and 23 deletions

View File

@@ -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)),
};
}

View File

@@ -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;
}

View File

@@ -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,
);
});

View File

@@ -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;
}
}

View File

@@ -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,

View File

@@ -127,9 +127,9 @@ export class Fido2ClientService<ParentWindowReference>
}
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");
}

View File

@@ -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 {