1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-19 15:57:42 +01:00

fido2-utils: fix BufferSource conversions (#11784)

The original implementation of bufferSourceToUint8Array was incorrect as
it did not consider that TypedArray instances represent a view of the
underlying ArrayBuffer which does not necessarily cover the entire
backing ArrayBuffer. This resulted in the output of this function
containing data which would not be logically contained in the input.

This was partially fixed by #8787 for the common case of the input
already being an Uint8Array, but it was still broken for any other
TypedArrays. But #8222 introduced another copy of the original broken
code, breaking the Uint8Array case again.

Fix this once and hopefully for the last time with a correct
implementation of bufferSourceToUint8Array and using that in the
appropriate places instead of open-coding it. In addition there are now
tests which exercise most edge cases with regards to ArrayBuffer and
TypedArrays.
This commit is contained in:
Lorenz Brun 2024-11-11 20:54:36 +01:00 committed by GitHub
parent a5294bed3d
commit 6d89c0f157
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 33 additions and 12 deletions

View File

@ -4,6 +4,36 @@ describe("Fido2 Utils", () => {
const asciiHelloWorldArray = [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100];
const b64HelloWorldString = "aGVsbG8gd29ybGQ=";
describe("bufferSourceToUint8Array(..)", () => {
it("should convert an ArrayBuffer", () => {
const buffer = new Uint8Array(asciiHelloWorldArray).buffer;
const out = Fido2Utils.bufferSourceToUint8Array(buffer);
expect(out).toEqual(new Uint8Array(asciiHelloWorldArray));
});
it("should convert an ArrayBuffer slice", () => {
const buffer = new Uint8Array(asciiHelloWorldArray).buffer.slice(8);
const out = Fido2Utils.bufferSourceToUint8Array(buffer);
expect(out).toEqual(new Uint8Array([114, 108, 100])); // 8th byte onwards
});
it("should pass through an Uint8Array", () => {
const typedArray = new Uint8Array(asciiHelloWorldArray);
const out = Fido2Utils.bufferSourceToUint8Array(typedArray);
expect(out).toEqual(new Uint8Array(asciiHelloWorldArray));
});
it("should preserve the view of TypedArray", () => {
const buffer = new Uint8Array(asciiHelloWorldArray).buffer;
const input = new Uint8Array(buffer, 8, 1);
const out = Fido2Utils.bufferSourceToUint8Array(input);
expect(out).toEqual(new Uint8Array([114]));
});
it("should convert different TypedArrays", () => {
const buffer = new Uint8Array(asciiHelloWorldArray).buffer;
const input = new Uint16Array(buffer, 8, 1);
const out = Fido2Utils.bufferSourceToUint8Array(input);
expect(out).toEqual(new Uint8Array([114, 108]));
});
});
describe("fromBufferToB64(...)", () => {
it("should convert an ArrayBuffer to a b64 string", () => {
const buffer = new Uint8Array(asciiHelloWorldArray).buffer;

View File

@ -1,13 +1,6 @@
export class Fido2Utils {
static bufferToString(bufferSource: BufferSource): string {
let buffer: Uint8Array;
if (bufferSource instanceof ArrayBuffer || bufferSource.buffer === undefined) {
buffer = new Uint8Array(bufferSource as ArrayBuffer);
} else {
buffer = new Uint8Array(bufferSource.buffer);
}
return Fido2Utils.fromBufferToB64(buffer)
return Fido2Utils.fromBufferToB64(Fido2Utils.bufferSourceToUint8Array(bufferSource))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
@ -18,12 +11,10 @@ export class Fido2Utils {
}
static bufferSourceToUint8Array(bufferSource: BufferSource): Uint8Array {
if (bufferSource instanceof Uint8Array) {
return bufferSource;
} else if (Fido2Utils.isArrayBuffer(bufferSource)) {
if (Fido2Utils.isArrayBuffer(bufferSource)) {
return new Uint8Array(bufferSource);
} else {
return new Uint8Array(bufferSource.buffer);
return new Uint8Array(bufferSource.buffer, bufferSource.byteOffset, bufferSource.byteLength);
}
}