mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 21:33:27 +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:
@@ -209,7 +209,7 @@ export class DesktopAutofillService implements OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
request.credentialId = Array.from(
|
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,
|
response: Fido2AuthenticatorGetAssertionResult,
|
||||||
): autofill.PasskeyAssertionResponse {
|
): autofill.PasskeyAssertionResponse {
|
||||||
return {
|
return {
|
||||||
userHandle: Array.from(response.selectedCredential.userHandle),
|
userHandle: Array.from(new Uint8Array(response.selectedCredential.userHandle)),
|
||||||
rpId: request.rpId,
|
rpId: request.rpId,
|
||||||
signature: Array.from(response.signature),
|
signature: Array.from(new Uint8Array(response.signature)),
|
||||||
clientDataHash: request.clientDataHash,
|
clientDataHash: request.clientDataHash,
|
||||||
authenticatorData: Array.from(response.authenticatorData),
|
authenticatorData: Array.from(new Uint8Array(response.authenticatorData)),
|
||||||
credentialId: Array.from(response.selectedCredential.id),
|
credentialId: Array.from(new Uint8Array(response.selectedCredential.id)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export class Fido2AuthenticatorError extends Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface PublicKeyCredentialDescriptor {
|
export interface PublicKeyCredentialDescriptor {
|
||||||
id: Uint8Array;
|
id: ArrayBuffer;
|
||||||
transports?: ("ble" | "hybrid" | "internal" | "nfc" | "usb")[];
|
transports?: ("ble" | "hybrid" | "internal" | "nfc" | "usb")[];
|
||||||
type: "public-key";
|
type: "public-key";
|
||||||
}
|
}
|
||||||
@@ -155,9 +155,9 @@ export interface Fido2AuthenticatorGetAssertionParams {
|
|||||||
|
|
||||||
export interface Fido2AuthenticatorGetAssertionResult {
|
export interface Fido2AuthenticatorGetAssertionResult {
|
||||||
selectedCredential: {
|
selectedCredential: {
|
||||||
id: Uint8Array;
|
id: ArrayBuffer;
|
||||||
userHandle?: Uint8Array;
|
userHandle?: ArrayBuffer;
|
||||||
};
|
};
|
||||||
authenticatorData: Uint8Array;
|
authenticatorData: ArrayBuffer;
|
||||||
signature: Uint8Array;
|
signature: ArrayBuffer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ describe("credential-id-utils", () => {
|
|||||||
new Uint8Array([
|
new Uint8Array([
|
||||||
0x08, 0xd7, 0x0b, 0x74, 0xe9, 0xf5, 0x45, 0x22, 0xa4, 0x25, 0xe5, 0xdc, 0xd4, 0x01, 0x07,
|
0x08, 0xd7, 0x0b, 0x74, 0xe9, 0xf5, 0x45, 0x22, 0xa4, 0x25, 0xe5, 0xdc, 0xd4, 0x01, 0x07,
|
||||||
0xe7,
|
0xe7,
|
||||||
]),
|
]).buffer,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ describe("credential-id-utils", () => {
|
|||||||
new Uint8Array([
|
new Uint8Array([
|
||||||
0x08, 0xd7, 0x0b, 0x74, 0xe9, 0xf5, 0x45, 0x22, 0xa4, 0x25, 0xe5, 0xdc, 0xd4, 0x01, 0x07,
|
0x08, 0xd7, 0x0b, 0x74, 0xe9, 0xf5, 0x45, 0x22, 0xa4, 0x25, 0xe5, 0xdc, 0xd4, 0x01, 0x07,
|
||||||
0xe7,
|
0xe7,
|
||||||
]),
|
]).buffer,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
import { Fido2Utils } from "./fido2-utils";
|
import { Fido2Utils } from "./fido2-utils";
|
||||||
import { guidToRawFormat } from "./guid-utils";
|
import { guidToRawFormat } from "./guid-utils";
|
||||||
|
|
||||||
export function parseCredentialId(encodedCredentialId: string): Uint8Array {
|
export function parseCredentialId(encodedCredentialId: string): ArrayBuffer {
|
||||||
try {
|
try {
|
||||||
if (encodedCredentialId.startsWith("b64.")) {
|
if (encodedCredentialId.startsWith("b64.")) {
|
||||||
return Fido2Utils.stringToBuffer(encodedCredentialId.slice(4));
|
return Fido2Utils.stringToBuffer(encodedCredentialId.slice(4));
|
||||||
}
|
}
|
||||||
|
|
||||||
return guidToRawFormat(encodedCredentialId);
|
return guidToRawFormat(encodedCredentialId).buffer;
|
||||||
} catch {
|
} catch {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -18,13 +18,16 @@ export function parseCredentialId(encodedCredentialId: string): Uint8Array {
|
|||||||
/**
|
/**
|
||||||
* Compares two credential IDs for equality.
|
* Compares two credential IDs for equality.
|
||||||
*/
|
*/
|
||||||
export function compareCredentialIds(a: Uint8Array, b: Uint8Array): boolean {
|
export function compareCredentialIds(a: ArrayBuffer, b: ArrayBuffer): boolean {
|
||||||
if (a.length !== b.length) {
|
if (a.byteLength !== b.byteLength) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < a.length; i++) {
|
const viewA = new Uint8Array(a);
|
||||||
if (a[i] !== b[i]) {
|
const viewB = new Uint8Array(b);
|
||||||
|
|
||||||
|
for (let i = 0; i < viewA.length; i++) {
|
||||||
|
if (viewA[i] !== viewB[i]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -514,7 +514,7 @@ async function getPrivateKeyFromFido2Credential(
|
|||||||
const keyBuffer = Fido2Utils.stringToBuffer(fido2Credential.keyValue);
|
const keyBuffer = Fido2Utils.stringToBuffer(fido2Credential.keyValue);
|
||||||
return await crypto.subtle.importKey(
|
return await crypto.subtle.importKey(
|
||||||
"pkcs8",
|
"pkcs8",
|
||||||
keyBuffer,
|
new Uint8Array(keyBuffer),
|
||||||
{
|
{
|
||||||
name: fido2Credential.keyAlgorithm,
|
name: fido2Credential.keyAlgorithm,
|
||||||
namedCurve: fido2Credential.keyCurve,
|
namedCurve: fido2Credential.keyCurve,
|
||||||
|
|||||||
@@ -127,9 +127,9 @@ export class Fido2ClientService<ParentWindowReference>
|
|||||||
}
|
}
|
||||||
|
|
||||||
const userId = Fido2Utils.stringToBuffer(params.user.id);
|
const userId = Fido2Utils.stringToBuffer(params.user.id);
|
||||||
if (userId.length < 1 || userId.length > 64) {
|
if (userId.byteLength < 1 || userId.byteLength > 64) {
|
||||||
this.logService?.warning(
|
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");
|
throw new TypeError("Invalid 'user.id' length");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ export class Fido2Utils {
|
|||||||
.replace(/=/g, "");
|
.replace(/=/g, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
static stringToBuffer(str: string): Uint8Array {
|
static stringToBuffer(str: string): ArrayBuffer {
|
||||||
return Fido2Utils.fromB64ToArray(Fido2Utils.fromUrlB64ToB64(str));
|
return Fido2Utils.fromB64ToArray(Fido2Utils.fromUrlB64ToB64(str)).buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bufferSourceToUint8Array(bufferSource: BufferSource): Uint8Array {
|
static bufferSourceToUint8Array(bufferSource: BufferSource): Uint8Array {
|
||||||
|
|||||||
Reference in New Issue
Block a user