Skip to content

Commit ff86606

Browse files
panvaaduh95
authored andcommitted
crypto: copy detached parameters as empty
Treat detached BufferSource parameters as empty byte sequences during algorithm normalization, including detached DataViews. Signed-off-by: Filip Skokan <panva.ip@gmail.com> Assisted-by: Codex PR-URL: #66237 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
1 parent 1314d27 commit ff86606

2 files changed

Lines changed: 69 additions & 10 deletions

File tree

‎lib/internal/crypto/util.js‎

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const {
44
ArrayBufferIsView,
55
ArrayBufferPrototypeGetByteLength,
6+
ArrayBufferPrototypeGetDetached,
67
ArrayPrototypeIncludes,
78
ArrayPrototypePush,
89
ArrayPrototypeSlice,
@@ -106,6 +107,7 @@ const {
106107

107108
const {
108109
isDataView,
110+
isArrayBuffer,
109111
isArrayBufferView,
110112
isAnyArrayBuffer,
111113
isPromise,
@@ -866,19 +868,43 @@ function getDataViewOrTypedArrayByteLength(V) {
866868
}
867869

868870
function getBufferSourceByteLength(V) {
869-
return ArrayBufferIsView(V) ?
870-
getDataViewOrTypedArrayByteLength(V) :
871-
ArrayBufferPrototypeGetByteLength(V);
871+
// ArrayBuffer and typed array lengths already become zero when detached.
872+
if (!ArrayBufferIsView(V))
873+
return ArrayBufferPrototypeGetByteLength(V);
874+
if (!isDataView(V))
875+
return TypedArrayPrototypeGetByteLength(V);
876+
const buffer = DataViewPrototypeGetBuffer(V);
877+
if (isArrayBuffer(buffer) && ArrayBufferPrototypeGetDetached(buffer))
878+
return 0;
879+
return DataViewPrototypeGetByteLength(V);
872880
}
873881

874882
function getBufferSourceBytes(V) {
875-
return ArrayBufferIsView(V) ?
876-
new Uint8Array(
877-
getDataViewOrTypedArrayBuffer(V),
878-
getDataViewOrTypedArrayByteOffset(V),
879-
getDataViewOrTypedArrayByteLength(V),
880-
) :
881-
new Uint8Array(V, 0, ArrayBufferPrototypeGetByteLength(V));
883+
if (!ArrayBufferIsView(V)) {
884+
const length = ArrayBufferPrototypeGetByteLength(V);
885+
if (length === 0 && ArrayBufferPrototypeGetDetached(V))
886+
return new Uint8Array(0);
887+
return new Uint8Array(V, 0, length);
888+
}
889+
890+
let buffer;
891+
let offset;
892+
let length;
893+
if (isDataView(V)) {
894+
buffer = DataViewPrototypeGetBuffer(V);
895+
if (isArrayBuffer(buffer) && ArrayBufferPrototypeGetDetached(buffer))
896+
return new Uint8Array(0);
897+
offset = DataViewPrototypeGetByteOffset(V);
898+
length = DataViewPrototypeGetByteLength(V);
899+
} else {
900+
buffer = TypedArrayPrototypeGetBuffer(V);
901+
offset = TypedArrayPrototypeGetByteOffset(V);
902+
length = TypedArrayPrototypeGetByteLength(V);
903+
if (length === 0 && isArrayBuffer(buffer) &&
904+
ArrayBufferPrototypeGetDetached(buffer))
905+
return new Uint8Array(0);
906+
}
907+
return new Uint8Array(buffer, offset, length);
882908
}
883909

884910
function getOptionalByteLength(V) {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
if (!common.hasCrypto)
5+
common.skip('missing crypto');
6+
7+
const assert = require('assert');
8+
const { subtle } = globalThis.crypto;
9+
10+
function detached(kind) {
11+
const buffer = new ArrayBuffer(16);
12+
const value = kind === 'ArrayBuffer' ? buffer :
13+
kind === 'DataView' ? new DataView(buffer) : new Uint8Array(buffer);
14+
buffer.transfer();
15+
return value;
16+
}
17+
18+
(async () => {
19+
const empty = new Uint8Array(0);
20+
const input = new Uint8Array(16);
21+
const key = await subtle.importKey('raw', input, 'HKDF', false, ['deriveBits']);
22+
const algorithm = { name: 'HKDF', hash: 'SHA-256', salt: empty, info: empty };
23+
const expected = await subtle.deriveBits(algorithm, key, 256);
24+
const digest = await subtle.digest('SHA-256', empty);
25+
for (const kind of ['ArrayBuffer', 'Uint8Array', 'DataView']) {
26+
for (const member of ['salt', 'info']) {
27+
assert.deepStrictEqual(await subtle.deriveBits({
28+
...algorithm, [member]: detached(kind),
29+
}, key, 256), expected);
30+
}
31+
assert.deepStrictEqual(await subtle.digest('SHA-256', detached(kind)), digest);
32+
}
33+
})().then(common.mustCall());

0 commit comments

Comments
 (0)