Skip to content

Commit a312e70

Browse files
panvaRafaelGSS
authored andcommitted
crypto: prepare webcrypto key import/export for modern algorithms
PR-URL: #59284 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
1 parent 95b8b7e commit a312e70

File tree

8 files changed

+125
-97
lines changed

8 files changed

+125
-97
lines changed

lib/internal/crypto/aes.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,7 @@ function aesImportKey(
285285
break;
286286
}
287287
default:
288-
throw lazyDOMException(
289-
`Unable to import AES key with format ${format}`,
290-
'NotSupportedError');
288+
return undefined;
291289
}
292290

293291
if (length === undefined) {

lib/internal/crypto/cfrg.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,8 @@ function cfrgImportKey(
324324
keyObject = createCFRGRawKey(name, keyData, true);
325325
break;
326326
}
327+
default:
328+
return undefined;
327329
}
328330

329331
if (keyObject.asymmetricKeyType !== name.toLowerCase()) {

lib/internal/crypto/ec.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ function ecImportKey(
250250
keyObject = createECPublicKeyRaw(namedCurve, keyData);
251251
break;
252252
}
253+
default:
254+
return undefined;
253255
}
254256

255257
switch (algorithm.name) {

lib/internal/crypto/keys.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -922,15 +922,11 @@ function importGenericSecretKey(
922922
keyObject = createSecretKey(keyData);
923923
break;
924924
}
925+
default:
926+
return undefined;
925927
}
926928

927-
if (keyObject) {
928-
return new InternalCryptoKey(keyObject, { name }, keyUsages, false);
929-
}
930-
931-
throw lazyDOMException(
932-
`Unable to import ${name} key with format ${format}`,
933-
'NotSupportedError');
929+
return new InternalCryptoKey(keyObject, { name }, keyUsages, false);
934930
}
935931

936932
module.exports = {

lib/internal/crypto/mac.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ function hmacImportKey(
143143
break;
144144
}
145145
default:
146-
throw lazyDOMException(`Unable to import HMAC key with format ${format}`);
146+
return undefined;
147147
}
148148

149149
const { length } = keyObject[kHandle].keyDetail({});

lib/internal/crypto/rsa.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,9 +305,7 @@ function rsaImportKey(
305305
break;
306306
}
307307
default:
308-
throw lazyDOMException(
309-
`Unable to import RSA key with format ${format}`,
310-
'NotSupportedError');
308+
return undefined;
311309
}
312310

313311
if (keyObject.asymmetricKeyType !== 'rsa') {

lib/internal/crypto/util.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,20 @@ const kSupportedAlgorithms = {
189189
'Ed25519': null,
190190
'X25519': null,
191191
},
192+
'exportKey': {
193+
'RSASSA-PKCS1-v1_5': null,
194+
'RSA-PSS': null,
195+
'RSA-OAEP': null,
196+
'ECDSA': null,
197+
'ECDH': null,
198+
'HMAC': null,
199+
'AES-CTR': null,
200+
'AES-CBC': null,
201+
'AES-GCM': null,
202+
'AES-KW': null,
203+
'Ed25519': null,
204+
'X25519': null,
205+
},
192206
'sign': {
193207
'RSASSA-PKCS1-v1_5': null,
194208
'RSA-PSS': 'RsaPssParams',
@@ -259,12 +273,14 @@ const experimentalAlgorithms = ObjectEntries({
259273
generateKey: null,
260274
importKey: null,
261275
deriveBits: 'EcdhKeyDeriveParams',
276+
exportKey: null,
262277
},
263278
'Ed448': {
264279
generateKey: null,
265280
sign: 'Ed448Params',
266281
verify: 'Ed448Params',
267282
importKey: null,
283+
exportKey: null,
268284
},
269285
});
270286

lib/internal/crypto/webcrypto.js

Lines changed: 99 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -322,36 +322,25 @@ async function exportKeySpki(key) {
322322
case 'RSA-PSS':
323323
// Fall through
324324
case '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);
330327
case 'ECDSA':
331328
// Fall through
332329
case '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);
338332
case 'Ed25519':
339333
// Fall through
340334
case 'Ed448':
341335
// Fall through
342336
case 'X25519':
343337
// Fall through
344338
case '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
}
356345

357346
async function exportKeyPkcs8(key) {
@@ -361,60 +350,50 @@ async function exportKeyPkcs8(key) {
361350
case 'RSA-PSS':
362351
// Fall through
363352
case '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);
369355
case 'ECDSA':
370356
// Fall through
371357
case '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);
377360
case 'Ed25519':
378361
// Fall through
379362
case 'Ed448':
380363
// Fall through
381364
case 'X25519':
382365
// Fall through
383366
case '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
}
395373

396-
async function exportKeyRaw(key) {
374+
async function exportKeyRawPublic(key) {
397375
switch (key.algorithm.name) {
398376
case 'ECDSA':
399377
// Fall through
400378
case '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);
406381
case 'Ed25519':
407382
// Fall through
408383
case 'Ed448':
409384
// Fall through
410385
case 'X25519':
411386
// Fall through
412387
case '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) {
418397
case 'AES-CTR':
419398
// Fall through
420399
case 'AES-CBC':
@@ -424,71 +403,66 @@ async function exportKeyRaw(key) {
424403
case 'AES-KW':
425404
// Fall through
426405
case '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
}
434411

435412
async function exportKeyJWK(key) {
436-
const jwk = key[kKeyObject][kHandle].exportJwk({
413+
const parameters = {
437414
key_ops: key.usages,
438415
ext: key.extractable,
439-
}, true);
416+
};
440417
switch (key.algorithm.name) {
441418
case 'RSASSA-PKCS1-v1_5':
442-
jwk.alg = normalizeHashName(
419+
parameters.alg = normalizeHashName(
443420
key.algorithm.hash.name,
444421
normalizeHashName.kContextJwkRsa);
445-
return jwk;
422+
break;
446423
case 'RSA-PSS':
447-
jwk.alg = normalizeHashName(
424+
parameters.alg = normalizeHashName(
448425
key.algorithm.hash.name,
449426
normalizeHashName.kContextJwkRsaPss);
450-
return jwk;
427+
break;
451428
case 'RSA-OAEP':
452-
jwk.alg = normalizeHashName(
429+
parameters.alg = normalizeHashName(
453430
key.algorithm.hash.name,
454431
normalizeHashName.kContextJwkRsaOaep);
455-
return jwk;
432+
break;
456433
case 'ECDSA':
457434
// Fall through
458435
case 'ECDH':
459-
jwk.crv ||= key.algorithm.namedCurve;
460-
return jwk;
436+
// Fall through
461437
case 'X25519':
462438
// Fall through
463439
case 'X448':
464-
jwk.crv ||= key.algorithm.name;
465-
return jwk;
440+
break;
466441
case 'Ed25519':
467442
// Fall through
468443
case 'Ed448':
469-
jwk.crv ||= key.algorithm.name;
470-
jwk.alg = key.algorithm.name;
471-
return jwk;
444+
parameters.alg = key.algorithm.name;
445+
break;
472446
case 'AES-CTR':
473447
// Fall through
474448
case 'AES-CBC':
475449
// Fall through
476450
case 'AES-GCM':
477451
// Fall through
478452
case '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;
482456
case 'HMAC':
483-
jwk.alg = normalizeHashName(
457+
parameters.alg = normalizeHashName(
484458
key.algorithm.hash.name,
485459
normalizeHashName.kContextJwkHmac);
486-
return jwk;
460+
break;
487461
default:
488-
// Fall through
462+
return undefined;
489463
}
490464

491-
throw lazyDOMException('Not yet supported', 'NotSupportedError');
465+
return key[kKeyObject][kHandle].exportJwk(parameters, true);
492466
}
493467

494468
async function exportKey(format, key) {
@@ -506,17 +480,55 @@ async function exportKey(format, key) {
506480
context: '2nd argument',
507481
});
508482

483+
try {
484+
normalizeAlgorithm(key.algorithm, 'exportKey');
485+
} catch {
486+
throw lazyDOMException(
487+
`${key.algorithm.name} key export is not supported`, 'NotSupportedError');
488+
}
489+
509490
if (!key.extractable)
510491
throw lazyDOMException('key is not extractable', 'InvalidAccessException');
511492

493+
let result;
512494
switch (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
}
521533

522534
async function importKey(
@@ -603,8 +615,12 @@ async function importKey(
603615
extractable,
604616
keyUsages);
605617
break;
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
}
609625

610626
if ((result.type === 'secret' || result.type === 'private') && result.usages.length === 0) {

0 commit comments

Comments
 (0)