lib: refactor kSupportedAlgorithms · nodejs/node@93fc80a
@@ -171,185 +171,230 @@ const kNamedCurveAliases = {
171171'P-521': 'secp521r1',
172172};
173173174-const kSupportedAlgorithms = {
175-'digest': {
176-'SHA-1': null,
177-'SHA-256': null,
178-'SHA-384': null,
179-'SHA-512': null,
174+// Algorithm definitions organized by algorithm name
175+const kAlgorithmDefinitions = {
176+'AES-CBC': {
177+'generateKey': 'AesKeyGenParams',
178+'exportKey': null,
179+'importKey': null,
180+'encrypt': 'AesCbcParams',
181+'decrypt': 'AesCbcParams',
182+'get key length': 'AesDerivedKeyParams',
183+},
184+'AES-CTR': {
185+'generateKey': 'AesKeyGenParams',
186+'exportKey': null,
187+'importKey': null,
188+'encrypt': 'AesCtrParams',
189+'decrypt': 'AesCtrParams',
190+'get key length': 'AesDerivedKeyParams',
180191},
181-'generateKey': {
182-'RSASSA-PKCS1-v1_5': 'RsaHashedKeyGenParams',
183-'RSA-PSS': 'RsaHashedKeyGenParams',
184-'RSA-OAEP': 'RsaHashedKeyGenParams',
185-'ECDSA': 'EcKeyGenParams',
186-'ECDH': 'EcKeyGenParams',
187-'AES-CTR': 'AesKeyGenParams',
188-'AES-CBC': 'AesKeyGenParams',
189-'AES-GCM': 'AesKeyGenParams',
190-'HMAC': 'HmacKeyGenParams',
191-'Ed25519': null,
192-'X25519': null,
192+'AES-GCM': {
193+'generateKey': 'AesKeyGenParams',
194+'exportKey': null,
195+'importKey': null,
196+'encrypt': 'AeadParams',
197+'decrypt': 'AeadParams',
198+'get key length': 'AesDerivedKeyParams',
193199},
194-'exportKey': {
195-'RSASSA-PKCS1-v1_5': null,
196-'RSA-PSS': null,
197-'RSA-OAEP': null,
198-'ECDSA': null,
199-'ECDH': null,
200-'HMAC': null,
201-'AES-CTR': null,
202-'AES-CBC': null,
203-'AES-GCM': null,
204-'Ed25519': null,
205-'X25519': null,
200+'AES-KW': {
201+'generateKey': 'AesKeyGenParams',
202+'exportKey': null,
203+'importKey': null,
204+'get key length': 'AesDerivedKeyParams',
205+'wrapKey': null,
206+'unwrapKey': null,
206207},
207-'sign': {
208-'RSASSA-PKCS1-v1_5': null,
209-'RSA-PSS': 'RsaPssParams',
210-'ECDSA': 'EcdsaParams',
211-'HMAC': null,
212-'Ed25519': null,
208+'ChaCha20-Poly1305': {
209+'generateKey': null,
210+'exportKey': null,
211+'importKey': null,
212+'encrypt': 'AeadParams',
213+'decrypt': 'AeadParams',
214+'get key length': null,
213215},
214-'verify': {
215-'RSASSA-PKCS1-v1_5': null,
216-'RSA-PSS': 'RsaPssParams',
217-'ECDSA': 'EcdsaParams',
218-'HMAC': null,
219-'Ed25519': null,
216+'cSHAKE128': { 'digest': 'CShakeParams' },
217+'cSHAKE256': { 'digest': 'CShakeParams' },
218+'ECDH': {
219+'generateKey': 'EcKeyGenParams',
220+'exportKey': null,
221+'importKey': 'EcKeyImportParams',
222+'deriveBits': 'EcdhKeyDeriveParams',
220223},
221-'importKey': {
222-'RSASSA-PKCS1-v1_5': 'RsaHashedImportParams',
223-'RSA-PSS': 'RsaHashedImportParams',
224-'RSA-OAEP': 'RsaHashedImportParams',
225-'ECDSA': 'EcKeyImportParams',
226-'ECDH': 'EcKeyImportParams',
227-'HMAC': 'HmacImportParams',
228-'HKDF': null,
229-'PBKDF2': null,
230-'AES-CTR': null,
231-'AES-CBC': null,
232-'AES-GCM': null,
233-'Ed25519': null,
234-'X25519': null,
224+'ECDSA': {
225+'generateKey': 'EcKeyGenParams',
226+'exportKey': null,
227+'importKey': 'EcKeyImportParams',
228+'sign': 'EcdsaParams',
229+'verify': 'EcdsaParams',
235230},
236-'deriveBits': {
237-'HKDF': 'HkdfParams',
238-'PBKDF2': 'Pbkdf2Params',
239-'ECDH': 'EcdhKeyDeriveParams',
240-'X25519': 'EcdhKeyDeriveParams',
231+'Ed25519': {
232+'generateKey': null,
233+'exportKey': null,
234+'importKey': null,
235+'sign': null,
236+'verify': null,
241237},
242-'encrypt': {
243-'RSA-OAEP': 'RsaOaepParams',
244-'AES-CBC': 'AesCbcParams',
245-'AES-GCM': 'AeadParams',
246-'AES-CTR': 'AesCtrParams',
238+'Ed448': {
239+'generateKey': null,
240+'exportKey': null,
241+'importKey': null,
242+'sign': 'Ed448Params',
243+'verify': 'Ed448Params',
247244},
248-'decrypt': {
249-'RSA-OAEP': 'RsaOaepParams',
250-'AES-CBC': 'AesCbcParams',
251-'AES-GCM': 'AeadParams',
252-'AES-CTR': 'AesCtrParams',
245+'HKDF': {
246+'importKey': null,
247+'deriveBits': 'HkdfParams',
248+'get key length': null,
253249},
254-'get key length': {
255-'AES-CBC': 'AesDerivedKeyParams',
256-'AES-CTR': 'AesDerivedKeyParams',
257-'AES-GCM': 'AesDerivedKeyParams',
258-'HMAC': 'HmacImportParams',
259-'HKDF': null,
260-'PBKDF2': null,
250+'HMAC': {
251+'generateKey': 'HmacKeyGenParams',
252+'exportKey': null,
253+'importKey': 'HmacImportParams',
254+'sign': null,
255+'verify': null,
256+'get key length': 'HmacImportParams',
261257},
262-'wrapKey': {},
263-'unwrapKey': {},
264-};
265-266-const conditionalAlgorithms = ObjectEntries({
267-'AES-KW': [{
268-'generateKey': 'AesKeyGenParams',
258+'ML-DSA-44': {
259+'generateKey': null,
269260'exportKey': null,
270261'importKey': null,
271-'get key length': 'AesDerivedKeyParams',
272-'wrapKey': null,
273-'unwrapKey': null,
274-}, !process.features.openssl_is_boringssl],
275-});
262+'sign': 'ContextParams',
263+'verify': 'ContextParams',
264+},
265+'ML-DSA-65': {
266+'generateKey': null,
267+'exportKey': null,
268+'importKey': null,
269+'sign': 'ContextParams',
270+'verify': 'ContextParams',
271+},
272+'ML-DSA-87': {
273+'generateKey': null,
274+'exportKey': null,
275+'importKey': null,
276+'sign': 'ContextParams',
277+'verify': 'ContextParams',
278+},
279+'PBKDF2': {
280+'importKey': null,
281+'deriveBits': 'Pbkdf2Params',
282+'get key length': null,
283+},
284+'RSA-OAEP': {
285+'generateKey': 'RsaHashedKeyGenParams',
286+'exportKey': null,
287+'importKey': 'RsaHashedImportParams',
288+'encrypt': 'RsaOaepParams',
289+'decrypt': 'RsaOaepParams',
290+},
291+'RSA-PSS': {
292+'generateKey': 'RsaHashedKeyGenParams',
293+'exportKey': null,
294+'importKey': 'RsaHashedImportParams',
295+'sign': 'RsaPssParams',
296+'verify': 'RsaPssParams',
297+},
298+'RSASSA-PKCS1-v1_5': {
299+'generateKey': 'RsaHashedKeyGenParams',
300+'exportKey': null,
301+'importKey': 'RsaHashedImportParams',
302+'sign': null,
303+'verify': null,
304+},
305+'SHA-1': { 'digest': null },
306+'SHA-256': { 'digest': null },
307+'SHA-384': { 'digest': null },
308+'SHA-512': { 'digest': null },
309+'SHA3-256': { 'digest': null },
310+'SHA3-384': { 'digest': null },
311+'SHA3-512': { 'digest': null },
312+'X25519': {
313+'generateKey': null,
314+'exportKey': null,
315+'importKey': null,
316+'deriveBits': 'EcdhKeyDeriveParams',
317+},
318+'X448': {
319+'generateKey': null,
320+'exportKey': null,
321+'importKey': null,
322+'deriveBits': 'EcdhKeyDeriveParams',
323+},
324+};
276325277-for (let i = 0; i < conditionalAlgorithms.length; i++) {
278-if (conditionalAlgorithms[i][1][1]) {
279-const name = conditionalAlgorithms[i][0];
280-const ops = ObjectEntries(conditionalAlgorithms[i][1][0]);
281-for (let j = 0; j < ops.length; j++) {
282-const { 0: op, 1: dict } = ops[j];
283-kSupportedAlgorithms[op][name] = dict;
284-}
285-}
286-}
326+// Conditionally supported algorithms
327+const conditionalAlgorithms = {
328+'AES-KW': !process.features.openssl_is_boringssl,
329+'ChaCha20-Poly1305': !process.features.openssl_is_boringssl ||
330+ArrayPrototypeIncludes(getCiphers(), 'chacha20-poly1305'),
331+'cSHAKE128': !process.features.openssl_is_boringssl ||
332+ArrayPrototypeIncludes(getHashes(), 'shake128'),
333+'cSHAKE256': !process.features.openssl_is_boringssl ||
334+ArrayPrototypeIncludes(getHashes(), 'shake256'),
335+'Ed448': !process.features.openssl_is_boringssl,
336+'ML-DSA-44': !!EVP_PKEY_ML_DSA_44,
337+'ML-DSA-65': !!EVP_PKEY_ML_DSA_65,
338+'ML-DSA-87': !!EVP_PKEY_ML_DSA_87,
339+'SHA3-256': !process.features.openssl_is_boringssl ||
340+ArrayPrototypeIncludes(getHashes(), 'sha3-256'),
341+'SHA3-384': !process.features.openssl_is_boringssl ||
342+ArrayPrototypeIncludes(getHashes(), 'sha3-384'),
343+'SHA3-512': !process.features.openssl_is_boringssl ||
344+ArrayPrototypeIncludes(getHashes(), 'sha3-512'),
345+'X448': !process.features.openssl_is_boringssl,
346+};
287347288-const experimentalAlgorithms = ObjectEntries({});
289-290-if (!process.features.openssl_is_boringssl) {
291-ArrayPrototypePush(experimentalAlgorithms,
292-['Ed448', {
293-generateKey: null,
294-sign: 'Ed448Params',
295-verify: 'Ed448Params',
296-importKey: null,
297-exportKey: null,
298-}],
299-['X448', {
300-generateKey: null,
301-importKey: null,
302-deriveBits: 'EcdhKeyDeriveParams',
303-exportKey: null,
304-}],
305-['cSHAKE128', { digest: 'CShakeParams' }],
306-['cSHAKE256', { digest: 'CShakeParams' }],
307-['ChaCha20-Poly1305', {
308-'encrypt': 'AeadParams',
309-'decrypt': 'AeadParams',
310-'generateKey': null,
311-'importKey': null,
312-'exportKey': null,
313-'get key length': null,
314-}],
315-['SHA3-256', { digest: null }],
316-['SHA3-384', { digest: null }],
317-['SHA3-512', { digest: null }],
318-);
319-}
348+// Experimental algorithms
349+const experimentalAlgorithms = [
350+'ChaCha20-Poly1305',
351+'cSHAKE128',
352+'cSHAKE256',
353+'Ed448',
354+'ML-DSA-44',
355+'ML-DSA-65',
356+'ML-DSA-87',
357+'SHA3-256',
358+'SHA3-384',
359+'SHA3-512',
360+'X448',
361+];
362+363+// Transform the algorithm definitions into the operation-keyed structure
364+function createSupportedAlgorithms(algorithmDefs) {
365+const result = {};
366+367+for (const { 0: algorithmName, 1: operations } of ObjectEntries(algorithmDefs)) {
368+// Skip algorithms that are conditionally not supported
369+if (ObjectPrototypeHasOwnProperty(conditionalAlgorithms, algorithmName) &&
370+!conditionalAlgorithms[algorithmName]) {
371+continue;
372+}
320373321-for (const { 0: algorithm, 1: nid } of [
322-['ML-DSA-44', EVP_PKEY_ML_DSA_44],
323-['ML-DSA-65', EVP_PKEY_ML_DSA_65],
324-['ML-DSA-87', EVP_PKEY_ML_DSA_87],
325-]) {
326-if (nid) {
327-ArrayPrototypePush(experimentalAlgorithms, [algorithm, {
328-generateKey: null,
329-sign: 'ContextParams',
330-verify: 'ContextParams',
331-importKey: null,
332-exportKey: null,
333-}]);
374+for (const { 0: operation, 1: dict } of ObjectEntries(operations)) {
375+result[operation] ||= {};
376+377+// Add experimental warnings for experimental algorithms
378+if (ArrayPrototypeIncludes(experimentalAlgorithms, algorithmName)) {
379+ObjectDefineProperty(result[operation], algorithmName, {
380+get() {
381+emitExperimentalWarning(`The ${algorithmName} Web Crypto API algorithm`);
382+return dict;
383+},
384+__proto__: null,
385+enumerable: true,
386+});
387+} else {
388+result[operation][algorithmName] = dict;
389+}
390+}
334391}
335-}
336392337-for (let i = 0; i < experimentalAlgorithms.length; i++) {
338-const name = experimentalAlgorithms[i][0];
339-const ops = ObjectEntries(experimentalAlgorithms[i][1]);
340-for (let j = 0; j < ops.length; j++) {
341-const { 0: op, 1: dict } = ops[j];
342-ObjectDefineProperty(kSupportedAlgorithms[op], name, {
343-get() {
344-emitExperimentalWarning(`The ${name} Web Crypto API algorithm`);
345-return dict;
346-},
347-__proto__: null,
348-enumerable: true,
349-});
350-}
393+return result;
351394}
352395396+const kSupportedAlgorithms = createSupportedAlgorithms(kAlgorithmDefinitions);
397+353398const simpleAlgorithmDictionaries = {
354399AeadParams: { iv: 'BufferSource', additionalData: 'BufferSource' },
355400RsaHashedKeyGenParams: { hash: 'HashAlgorithmIdentifier' },