Skip to content

Commit a3969a1

Browse files
committed
crypto: deduplicate and canonicalize CryptoKey usages
Fixes: #62899 Signed-off-by: Filip Skokan <[email protected]>
1 parent 9531947 commit a3969a1

12 files changed

Lines changed: 617 additions & 25 deletions

File tree

lib/internal/crypto/aes.js

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

33
const {
4-
ArrayFrom,
54
ArrayPrototypePush,
65
SafeSet,
76
} = primordials;
@@ -210,7 +209,7 @@ async function aesGenerateKey(algorithm, extractable, keyUsages) {
210209
return new InternalCryptoKey(
211210
key,
212211
{ name, length },
213-
ArrayFrom(usagesSet),
212+
usagesSet,
214213
extractable);
215214
}
216215

@@ -285,7 +284,7 @@ function aesImportKey(
285284
return new InternalCryptoKey(
286285
keyObject,
287286
{ name, length },
288-
keyUsages,
287+
usagesSet,
289288
extractable);
290289
}
291290

lib/internal/crypto/cfrg.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ async function cfrgGenerateKey(algorithm, extractable, keyUsages) {
134134
case 'X25519':
135135
// Fall through
136136
case 'X448':
137-
publicUsages = [];
137+
publicUsages = new SafeSet();
138138
privateUsages = getUsagesUnion(usageSet, 'deriveKey', 'deriveBits');
139139
break;
140140
}
@@ -245,7 +245,7 @@ function cfrgImportKey(
245245
return new InternalCryptoKey(
246246
keyObject,
247247
{ name },
248-
keyUsages,
248+
usagesSet,
249249
extractable);
250250
}
251251

lib/internal/crypto/chacha20_poly1305.js

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

33
const {
4-
ArrayFrom,
54
SafeSet,
65
} = primordials;
76

@@ -81,7 +80,7 @@ async function c20pGenerateKey(algorithm, extractable, keyUsages) {
8180
return new InternalCryptoKey(
8281
createSecretKey(keyData),
8382
{ name },
84-
ArrayFrom(usagesSet),
83+
usagesSet,
8584
extractable);
8685
}
8786

@@ -140,7 +139,7 @@ function c20pImportKey(
140139
return new InternalCryptoKey(
141140
keyObject,
142141
{ name },
143-
keyUsages,
142+
usagesSet,
144143
extractable);
145144
}
146145

lib/internal/crypto/ec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ async function ecGenerateKey(algorithm, extractable, keyUsages) {
119119
privateUsages = getUsagesUnion(usageSet, 'sign');
120120
break;
121121
case 'ECDH':
122-
publicUsages = [];
122+
publicUsages = new SafeSet();
123123
privateUsages = getUsagesUnion(usageSet, 'deriveKey', 'deriveBits');
124124
break;
125125
}
@@ -271,7 +271,7 @@ function ecImportKey(
271271
return new InternalCryptoKey(
272272
keyObject,
273273
{ name, namedCurve },
274-
keyUsages,
274+
usagesSet,
275275
extractable);
276276
}
277277

lib/internal/crypto/keys.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const {
6161
bigIntArrayToUnsignedBigInt,
6262
normalizeAlgorithm,
6363
hasAnyNotIn,
64+
getSortedUsages,
6465
} = require('internal/crypto/util');
6566

6667
const {
@@ -901,7 +902,7 @@ class InternalCryptoKey {
901902
keyObject,
902903
algorithm,
903904
extractable,
904-
keyUsages,
905+
getSortedUsages(new SafeSet(keyUsages)),
905906
);
906907
}
907908
}
@@ -967,7 +968,7 @@ function importGenericSecretKey(
967968
return undefined;
968969
}
969970

970-
return new InternalCryptoKey(keyObject, { name }, keyUsages, false);
971+
return new InternalCryptoKey(keyObject, { name }, usagesSet, false);
971972
}
972973

973974
module.exports = {

lib/internal/crypto/mac.js

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

33
const {
4-
ArrayFrom,
54
SafeSet,
65
StringPrototypeSubstring,
76
} = primordials;
@@ -81,7 +80,7 @@ async function hmacGenerateKey(algorithm, extractable, keyUsages) {
8180
return new InternalCryptoKey(
8281
key,
8382
{ name, length, hash },
84-
ArrayFrom(usageSet),
83+
usageSet,
8584
extractable);
8685
}
8786

@@ -115,7 +114,7 @@ async function kmacGenerateKey(algorithm, extractable, keyUsages) {
115114
return new InternalCryptoKey(
116115
createSecretKey(keyData),
117116
{ name, length },
118-
ArrayFrom(usageSet),
117+
usageSet,
119118
extractable);
120119
}
121120

@@ -196,7 +195,7 @@ function macImportKey(
196195
return new InternalCryptoKey(
197196
keyObject,
198197
algorithmObject,
199-
keyUsages,
198+
usagesSet,
200199
extractable);
201200
}
202201

lib/internal/crypto/ml_dsa.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ function mlDsaImportKey(
203203
return new InternalCryptoKey(
204204
keyObject,
205205
{ name },
206-
keyUsages,
206+
usagesSet,
207207
extractable);
208208
}
209209

lib/internal/crypto/ml_kem.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ async function mlKemGenerateKey(algorithm, extractable, keyUsages) {
6969
{ name: 'OperationError', cause: err });
7070
}
7171

72-
const publicUsages = getUsagesUnion(usageSet, 'encapsulateBits', 'encapsulateKey');
73-
const privateUsages = getUsagesUnion(usageSet, 'decapsulateBits', 'decapsulateKey');
72+
const publicUsages = getUsagesUnion(usageSet, 'encapsulateKey', 'encapsulateBits');
73+
const privateUsages = getUsagesUnion(usageSet, 'decapsulateKey', 'decapsulateBits');
7474

7575
const keyAlgorithm = { name };
7676

@@ -202,7 +202,7 @@ function mlKemImportKey(
202202
return new InternalCryptoKey(
203203
keyObject,
204204
{ name },
205-
keyUsages,
205+
usagesSet,
206206
extractable);
207207
}
208208

lib/internal/crypto/rsa.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ function rsaImportKey(
281281
modulusLength,
282282
publicExponent: new Uint8Array(publicExponent),
283283
hash: algorithm.hash,
284-
}, keyUsages, extractable);
284+
}, usagesSet, extractable);
285285
}
286286

287287
async function rsaSignVerify(key, data, { saltLength }, signature) {

lib/internal/crypto/util.js

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const {
1616
ObjectKeys,
1717
ObjectPrototypeHasOwnProperty,
1818
PromiseWithResolvers,
19+
SafeSet,
1920
StringPrototypeToUpperCase,
2021
Symbol,
2122
TypedArrayPrototypeGetBuffer,
@@ -718,14 +719,38 @@ function getStringOption(options, key) {
718719
}
719720

720721
function getUsagesUnion(usageSet, ...usages) {
721-
const newset = [];
722+
const newset = new SafeSet();
722723
for (let n = 0; n < usages.length; n++) {
723724
if (usageSet.has(usages[n]))
724-
ArrayPrototypePush(newset, usages[n]);
725+
newset.add(usages[n]);
725726
}
726727
return newset;
727728
}
728729

730+
const kCanonicalUsageOrder = new SafeSet([
731+
'encrypt', 'decrypt',
732+
'sign', 'verify',
733+
'deriveKey', 'deriveBits',
734+
'wrapKey', 'unwrapKey',
735+
'encapsulateKey', 'encapsulateBits',
736+
'decapsulateKey', 'decapsulateBits',
737+
]);
738+
739+
/**
740+
* Returns the usages from `usageSet` as an array in the canonical order
741+
* defined by {@link kCanonicalUsageOrder}.
742+
* @param {SafeSet<string>} usageSet
743+
* @returns {string[]}
744+
*/
745+
function getSortedUsages(usageSet) {
746+
const result = [];
747+
for (const usage of kCanonicalUsageOrder) {
748+
if (usageSet.has(usage))
749+
ArrayPrototypePush(result, usage);
750+
}
751+
return result;
752+
}
753+
729754
function getBlockSize(name) {
730755
switch (name) {
731756
case 'SHA-1':
@@ -841,6 +866,7 @@ module.exports = {
841866
getDigestSizeInBytes,
842867
getStringOption,
843868
getUsagesUnion,
869+
getSortedUsages,
844870
secureHeapUsed,
845871
getCachedHashId,
846872
getHashCache,

0 commit comments

Comments
 (0)