crypto: prepare webcrypto key import/export for modern algorithms · nodejs/node@a312e70
@@ -322,36 +322,25 @@ async function exportKeySpki(key) {
322322case 'RSA-PSS':
323323// Fall through
324324case 'RSA-OAEP':
325-if (key.type === 'public') {
326-return require('internal/crypto/rsa')
327-.rsaExportKey(key, kWebCryptoKeyFormatSPKI);
328-}
329-break;
325+return require('internal/crypto/rsa')
326+.rsaExportKey(key, kWebCryptoKeyFormatSPKI);
330327case 'ECDSA':
331328// Fall through
332329case 'ECDH':
333-if (key.type === 'public') {
334-return require('internal/crypto/ec')
335-.ecExportKey(key, kWebCryptoKeyFormatSPKI);
336-}
337-break;
330+return require('internal/crypto/ec')
331+.ecExportKey(key, kWebCryptoKeyFormatSPKI);
338332case 'Ed25519':
339333// Fall through
340334case 'Ed448':
341335// Fall through
342336case 'X25519':
343337// Fall through
344338case 'X448':
345-if (key.type === 'public') {
346-return require('internal/crypto/cfrg')
347-.cfrgExportKey(key, kWebCryptoKeyFormatSPKI);
348-}
349-break;
339+return require('internal/crypto/cfrg')
340+.cfrgExportKey(key, kWebCryptoKeyFormatSPKI);
341+default:
342+return undefined;
350343}
351-352-throw lazyDOMException(
353-`Unable to export a raw ${key.algorithm.name} ${key.type} key`,
354-'InvalidAccessError');
355344}
356345357346async function exportKeyPkcs8(key) {
@@ -361,60 +350,50 @@ async function exportKeyPkcs8(key) {
361350case 'RSA-PSS':
362351// Fall through
363352case 'RSA-OAEP':
364-if (key.type === 'private') {
365-return require('internal/crypto/rsa')
366-.rsaExportKey(key, kWebCryptoKeyFormatPKCS8);
367-}
368-break;
353+return require('internal/crypto/rsa')
354+.rsaExportKey(key, kWebCryptoKeyFormatPKCS8);
369355case 'ECDSA':
370356// Fall through
371357case 'ECDH':
372-if (key.type === 'private') {
373-return require('internal/crypto/ec')
374-.ecExportKey(key, kWebCryptoKeyFormatPKCS8);
375-}
376-break;
358+return require('internal/crypto/ec')
359+.ecExportKey(key, kWebCryptoKeyFormatPKCS8);
377360case 'Ed25519':
378361// Fall through
379362case 'Ed448':
380363// Fall through
381364case 'X25519':
382365// Fall through
383366case 'X448':
384-if (key.type === 'private') {
385-return require('internal/crypto/cfrg')
386-.cfrgExportKey(key, kWebCryptoKeyFormatPKCS8);
387-}
388-break;
367+return require('internal/crypto/cfrg')
368+.cfrgExportKey(key, kWebCryptoKeyFormatPKCS8);
369+default:
370+return undefined;
389371}
390-391-throw lazyDOMException(
392-`Unable to export a pkcs8 ${key.algorithm.name} ${key.type} key`,
393-'InvalidAccessError');
394372}
395373396-async function exportKeyRaw(key) {
374+async function exportKeyRawPublic(key) {
397375switch (key.algorithm.name) {
398376case 'ECDSA':
399377// Fall through
400378case 'ECDH':
401-if (key.type === 'public') {
402-return require('internal/crypto/ec')
403-.ecExportKey(key, kWebCryptoKeyFormatRaw);
404-}
405-break;
379+return require('internal/crypto/ec')
380+.ecExportKey(key, kWebCryptoKeyFormatRaw);
406381case 'Ed25519':
407382// Fall through
408383case 'Ed448':
409384// Fall through
410385case 'X25519':
411386// Fall through
412387case 'X448':
413-if (key.type === 'public') {
414-return require('internal/crypto/cfrg')
415-.cfrgExportKey(key, kWebCryptoKeyFormatRaw);
416-}
417-break;
388+return require('internal/crypto/cfrg')
389+.cfrgExportKey(key, kWebCryptoKeyFormatRaw);
390+default:
391+return undefined;
392+}
393+}
394+395+async function exportKeyRawSecret(key) {
396+switch (key.algorithm.name) {
418397case 'AES-CTR':
419398// Fall through
420399case 'AES-CBC':
@@ -424,71 +403,66 @@ async function exportKeyRaw(key) {
424403case 'AES-KW':
425404// Fall through
426405case 'HMAC':
427-return key[kKeyObject].export().buffer;
406+return key[kKeyObject][kHandle].export().buffer;
407+default:
408+return undefined;
428409}
429-430-throw lazyDOMException(
431-`Unable to export a raw ${key.algorithm.name} ${key.type} key`,
432-'InvalidAccessError');
433410}
434411435412async function exportKeyJWK(key) {
436-const jwk = key[kKeyObject][kHandle].exportJwk({
413+const parameters = {
437414key_ops: key.usages,
438415ext: key.extractable,
439-}, true);
416+};
440417switch (key.algorithm.name) {
441418case 'RSASSA-PKCS1-v1_5':
442-jwk.alg = normalizeHashName(
419+parameters.alg = normalizeHashName(
443420key.algorithm.hash.name,
444421normalizeHashName.kContextJwkRsa);
445-return jwk;
422+break;
446423case 'RSA-PSS':
447-jwk.alg = normalizeHashName(
424+parameters.alg = normalizeHashName(
448425key.algorithm.hash.name,
449426normalizeHashName.kContextJwkRsaPss);
450-return jwk;
427+break;
451428case 'RSA-OAEP':
452-jwk.alg = normalizeHashName(
429+parameters.alg = normalizeHashName(
453430key.algorithm.hash.name,
454431normalizeHashName.kContextJwkRsaOaep);
455-return jwk;
432+break;
456433case 'ECDSA':
457434// Fall through
458435case 'ECDH':
459-jwk.crv ||= key.algorithm.namedCurve;
460-return jwk;
436+// Fall through
461437case 'X25519':
462438// Fall through
463439case 'X448':
464-jwk.crv ||= key.algorithm.name;
465-return jwk;
440+break;
466441case 'Ed25519':
467442// Fall through
468443case 'Ed448':
469-jwk.crv ||= key.algorithm.name;
470-jwk.alg = key.algorithm.name;
471-return jwk;
444+parameters.alg = key.algorithm.name;
445+break;
472446case 'AES-CTR':
473447// Fall through
474448case 'AES-CBC':
475449// Fall through
476450case 'AES-GCM':
477451// Fall through
478452case 'AES-KW':
479-jwk.alg = require('internal/crypto/aes')
453+parameters.alg = require('internal/crypto/aes')
480454.getAlgorithmName(key.algorithm.name, key.algorithm.length);
481-return jwk;
455+break;
482456case 'HMAC':
483-jwk.alg = normalizeHashName(
457+parameters.alg = normalizeHashName(
484458key.algorithm.hash.name,
485459normalizeHashName.kContextJwkHmac);
486-return jwk;
460+break;
487461default:
488-// Fall through
462+return undefined;
489463}
490464491-throw lazyDOMException('Not yet supported', 'NotSupportedError');
465+return key[kKeyObject][kHandle].exportJwk(parameters, true);
492466}
493467494468async function exportKey(format, key) {
@@ -506,17 +480,55 @@ async function exportKey(format, key) {
506480context: '2nd argument',
507481});
508482483+try {
484+normalizeAlgorithm(key.algorithm, 'exportKey');
485+} catch {
486+throw lazyDOMException(
487+`${key.algorithm.name} key export is not supported`, 'NotSupportedError');
488+}
489+509490if (!key.extractable)
510491throw lazyDOMException('key is not extractable', 'InvalidAccessException');
511492493+let result;
512494switch (format) {
513-case 'spki': return exportKeySpki(key);
514-case 'pkcs8': return exportKeyPkcs8(key);
515-case 'jwk': return exportKeyJWK(key);
516-case 'raw': return exportKeyRaw(key);
495+case 'spki': {
496+if (key.type === 'public') {
497+result = await exportKeySpki(key);
498+}
499+break;
500+}
501+case 'pkcs8': {
502+if (key.type === 'private') {
503+result = await exportKeyPkcs8(key);
504+}
505+break;
506+}
507+case 'jwk': {
508+result = await exportKeyJWK(key);
509+break;
510+}
511+case 'raw': {
512+if (key.type === 'secret') {
513+result = await exportKeyRawSecret(key);
514+break;
515+}
516+517+if (key.type === 'public') {
518+result = await exportKeyRawPublic(key);
519+break;
520+}
521+break;
522+}
517523}
518-throw lazyDOMException(
519-'Export format is unsupported', 'NotSupportedError');
524+525+if (!result) {
526+throw lazyDOMException(
527+`Unable to export ${key.algorithm.name} ${key.type} key using ${format} format`,
528+'NotSupportedError');
529+}
530+531+return result;
520532}
521533522534async function importKey(
@@ -603,8 +615,12 @@ async function importKey(
603615extractable,
604616keyUsages);
605617break;
606-default:
607-throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
618+}
619+620+if (!result) {
621+throw lazyDOMException(
622+`Unable to import ${algorithm.name} using ${format} format`,
623+'NotSupportedError');
608624}
609625610626if ((result.type === 'secret' || result.type === 'private') && result.usages.length === 0) {