Skip to content

Commit 6d97ccd

Browse files
panvaaduh95
authored andcommitted
crypto: create key usage arrays without species
Build public usages and JWK key_ops from the native usage mask so array species cannot replace or mutate internal usage arrays. 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 2ac8c82 commit 6d97ccd

4 files changed

Lines changed: 37 additions & 9 deletions

File tree

‎lib/internal/crypto/kem_hybrids.js‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict';
22

33
const {
4-
ArrayPrototypeSlice,
54
BigInt,
65
PromiseWithResolvers,
76
SafeSet,
@@ -24,7 +23,7 @@ const {
2423
getCryptoKeySeedData,
2524
getCryptoKeySecondaryHandle,
2625
getCryptoKeyType,
27-
getCryptoKeyUsages,
26+
getCryptoKeyUsagesMask,
2827
InternalCryptoKey,
2928
} = require('internal/crypto/keys');
3029

@@ -51,6 +50,7 @@ const {
5150
const {
5251
getBufferSourceBytes,
5352
getUsagesMask,
53+
getUsagesFromMask,
5454
jobPromise,
5555
jobPromiseThen,
5656
resolveWebCryptoResult,
@@ -860,7 +860,7 @@ function exportJwkKey(key, rawEncapsulationKey, config) {
860860
kty: 'AKP',
861861
alg: config.name,
862862
pub: base64urlEncode(rawEncapsulationKey),
863-
key_ops: ArrayPrototypeSlice(getCryptoKeyUsages(key), 0),
863+
key_ops: getUsagesFromMask(getCryptoKeyUsagesMask(key)),
864864
ext: getCryptoKeyExtractable(key),
865865
};
866866
if (getCryptoKeyType(key) === 'private')

‎lib/internal/crypto/keys.js‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
const {
44
ArrayPrototypeMap,
5-
ArrayPrototypeSlice,
65
ObjectDefineProperties,
76
ObjectPrototypeHasOwnProperty,
87
ObjectSetPrototypeOf,
@@ -1252,7 +1251,7 @@ const {
12521251
type: getCryptoKeyType(this),
12531252
extractable: getCryptoKeyExtractable(this),
12541253
algorithm: cloneAlgorithm(getCryptoKeyAlgorithm(this)),
1255-
usages: ArrayPrototypeSlice(getCryptoKeyUsages(this), 0),
1254+
usages: getUsagesFromMask(getCryptoKeyUsagesMask(this)),
12561255
}, opts)}`;
12571256
}
12581257

@@ -1286,7 +1285,7 @@ const {
12861285
const slots = getSlots(this);
12871286
let cached = slots[kSlotClonedUsages];
12881287
if (cached === undefined) {
1289-
cached = ArrayPrototypeSlice(getCryptoKeyUsagesFromSlots(slots), 0);
1288+
cached = getUsagesFromMask(slots[kSlotUsagesMask]);
12901289
slots[kSlotClonedUsages] = cached;
12911290
}
12921291
return cached;

‎lib/internal/crypto/webcrypto.js‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
const {
44
ArrayBufferIsView,
55
ArrayIsArray,
6-
ArrayPrototypeSlice,
76
FunctionPrototypeCall,
87
JSONParse,
98
JSONStringify,
@@ -51,7 +50,6 @@ const {
5150
getCryptoKeyExtractable,
5251
getCryptoKeyHandle,
5352
getCryptoKeyType,
54-
getCryptoKeyUsages,
5553
getCryptoKeyUsagesMask,
5654
hasCryptoKeyUsage,
5755
importGenericSecretKey,
@@ -65,6 +63,7 @@ const {
6563
const {
6664
cleanupWebCryptoResult,
6765
getBlockSize,
66+
getUsagesFromMask,
6867
jobPromiseThen,
6968
normalizeAlgorithm,
7069
normalizeHashName,
@@ -795,7 +794,7 @@ function exportKeyJWK(key) {
795794
// `parameters` before native export populates key material. Delete it for
796795
// algorithms without a JWK alg value to keep the expected shape.
797796
const parameters = {
798-
key_ops: ArrayPrototypeSlice(getCryptoKeyUsages(key), 0),
797+
key_ops: getUsagesFromMask(getCryptoKeyUsagesMask(key)),
799798
ext: getCryptoKeyExtractable(key),
800799
alg,
801800
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
(async () => {
11+
const key = await subtle.importKey('raw', new Uint8Array(16), 'AES-GCM', true,
12+
['encrypt', 'decrypt']);
13+
const descriptor = Object.getOwnPropertyDescriptor(Array.prototype, 'constructor');
14+
let usages;
15+
let jwk;
16+
try {
17+
Object.defineProperty(Array.prototype, 'constructor', { get: common.mustNotCall() });
18+
usages = key.usages;
19+
jwk = await subtle.exportKey('jwk', key);
20+
} finally {
21+
Object.defineProperty(Array.prototype, 'constructor', descriptor);
22+
}
23+
assert.strictEqual(Object.getPrototypeOf(usages), Array.prototype);
24+
assert.strictEqual(key.usages, usages);
25+
assert.deepStrictEqual(usages, ['encrypt', 'decrypt']);
26+
assert.deepStrictEqual(jwk.key_ops, usages);
27+
usages.push('sign');
28+
assert.deepStrictEqual((await subtle.exportKey('jwk', key)).key_ops,
29+
['encrypt', 'decrypt']);
30+
})().then(common.mustCall());

0 commit comments

Comments
 (0)