Skip to content

Commit b557104

Browse files
panvaaduh95
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 3cc11fc commit b557104

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
@@ -327,36 +327,25 @@ async function exportKeySpki(key) {
327327
case 'RSA-PSS':
328328
// Fall through
329329
case 'RSA-OAEP':
330-
if (key.type === 'public') {
331-
return require('internal/crypto/rsa')
332-
.rsaExportKey(key, kWebCryptoKeyFormatSPKI);
333-
}
334-
break;
330+
return require('internal/crypto/rsa')
331+
.rsaExportKey(key, kWebCryptoKeyFormatSPKI);
335332
case 'ECDSA':
336333
// Fall through
337334
case 'ECDH':
338-
if (key.type === 'public') {
339-
return require('internal/crypto/ec')
340-
.ecExportKey(key, kWebCryptoKeyFormatSPKI);
341-
}
342-
break;
335+
return require('internal/crypto/ec')
336+
.ecExportKey(key, kWebCryptoKeyFormatSPKI);
343337
case 'Ed25519':
344338
// Fall through
345339
case 'Ed448':
346340
// Fall through
347341
case 'X25519':
348342
// Fall through
349343
case 'X448':
350-
if (key.type === 'public') {
351-
return require('internal/crypto/cfrg')
352-
.cfrgExportKey(key, kWebCryptoKeyFormatSPKI);
353-
}
354-
break;
344+
return require('internal/crypto/cfrg')
345+
.cfrgExportKey(key, kWebCryptoKeyFormatSPKI);
346+
default:
347+
return undefined;
355348
}
356-
357-
throw lazyDOMException(
358-
`Unable to export a raw ${key.algorithm.name} ${key.type} key`,
359-
'InvalidAccessError');
360349
}
361350

362351
async function exportKeyPkcs8(key) {
@@ -366,60 +355,50 @@ async function exportKeyPkcs8(key) {
366355
case 'RSA-PSS':
367356
// Fall through
368357
case 'RSA-OAEP':
369-
if (key.type === 'private') {
370-
return require('internal/crypto/rsa')
371-
.rsaExportKey(key, kWebCryptoKeyFormatPKCS8);
372-
}
373-
break;
358+
return require('internal/crypto/rsa')
359+
.rsaExportKey(key, kWebCryptoKeyFormatPKCS8);
374360
case 'ECDSA':
375361
// Fall through
376362
case 'ECDH':
377-
if (key.type === 'private') {
378-
return require('internal/crypto/ec')
379-
.ecExportKey(key, kWebCryptoKeyFormatPKCS8);
380-
}
381-
break;
363+
return require('internal/crypto/ec')
364+
.ecExportKey(key, kWebCryptoKeyFormatPKCS8);
382365
case 'Ed25519':
383366
// Fall through
384367
case 'Ed448':
385368
// Fall through
386369
case 'X25519':
387370
// Fall through
388371
case 'X448':
389-
if (key.type === 'private') {
390-
return require('internal/crypto/cfrg')
391-
.cfrgExportKey(key, kWebCryptoKeyFormatPKCS8);
392-
}
393-
break;
372+
return require('internal/crypto/cfrg')
373+
.cfrgExportKey(key, kWebCryptoKeyFormatPKCS8);
374+
default:
375+
return undefined;
394376
}
395-
396-
throw lazyDOMException(
397-
`Unable to export a pkcs8 ${key.algorithm.name} ${key.type} key`,
398-
'InvalidAccessError');
399377
}
400378

401-
async function exportKeyRaw(key) {
379+
async function exportKeyRawPublic(key) {
402380
switch (key.algorithm.name) {
403381
case 'ECDSA':
404382
// Fall through
405383
case 'ECDH':
406-
if (key.type === 'public') {
407-
return require('internal/crypto/ec')
408-
.ecExportKey(key, kWebCryptoKeyFormatRaw);
409-
}
410-
break;
384+
return require('internal/crypto/ec')
385+
.ecExportKey(key, kWebCryptoKeyFormatRaw);
411386
case 'Ed25519':
412387
// Fall through
413388
case 'Ed448':
414389
// Fall through
415390
case 'X25519':
416391
// Fall through
417392
case 'X448':
418-
if (key.type === 'public') {
419-
return require('internal/crypto/cfrg')
420-
.cfrgExportKey(key, kWebCryptoKeyFormatRaw);
421-
}
422-
break;
393+
return require('internal/crypto/cfrg')
394+
.cfrgExportKey(key, kWebCryptoKeyFormatRaw);
395+
default:
396+
return undefined;
397+
}
398+
}
399+
400+
async function exportKeyRawSecret(key) {
401+
switch (key.algorithm.name) {
423402
case 'AES-CTR':
424403
// Fall through
425404
case 'AES-CBC':
@@ -429,71 +408,66 @@ async function exportKeyRaw(key) {
429408
case 'AES-KW':
430409
// Fall through
431410
case 'HMAC':
432-
return key[kKeyObject].export().buffer;
411+
return key[kKeyObject][kHandle].export().buffer;
412+
default:
413+
return undefined;
433414
}
434-
435-
throw lazyDOMException(
436-
`Unable to export a raw ${key.algorithm.name} ${key.type} key`,
437-
'InvalidAccessError');
438415
}
439416

440417
async function exportKeyJWK(key) {
441-
const jwk = key[kKeyObject][kHandle].exportJwk({
418+
const parameters = {
442419
key_ops: key.usages,
443420
ext: key.extractable,
444-
}, true);
421+
};
445422
switch (key.algorithm.name) {
446423
case 'RSASSA-PKCS1-v1_5':
447-
jwk.alg = normalizeHashName(
424+
parameters.alg = normalizeHashName(
448425
key.algorithm.hash.name,
449426
normalizeHashName.kContextJwkRsa);
450-
return jwk;
427+
break;
451428
case 'RSA-PSS':
452-
jwk.alg = normalizeHashName(
429+
parameters.alg = normalizeHashName(
453430
key.algorithm.hash.name,
454431
normalizeHashName.kContextJwkRsaPss);
455-
return jwk;
432+
break;
456433
case 'RSA-OAEP':
457-
jwk.alg = normalizeHashName(
434+
parameters.alg = normalizeHashName(
458435
key.algorithm.hash.name,
459436
normalizeHashName.kContextJwkRsaOaep);
460-
return jwk;
437+
break;
461438
case 'ECDSA':
462439
// Fall through
463440
case 'ECDH':
464-
jwk.crv ||= key.algorithm.namedCurve;
465-
return jwk;
441+
// Fall through
466442
case 'X25519':
467443
// Fall through
468444
case 'X448':
469-
jwk.crv ||= key.algorithm.name;
470-
return jwk;
445+
break;
471446
case 'Ed25519':
472447
// Fall through
473448
case 'Ed448':
474-
jwk.crv ||= key.algorithm.name;
475-
jwk.alg = key.algorithm.name;
476-
return jwk;
449+
parameters.alg = key.algorithm.name;
450+
break;
477451
case 'AES-CTR':
478452
// Fall through
479453
case 'AES-CBC':
480454
// Fall through
481455
case 'AES-GCM':
482456
// Fall through
483457
case 'AES-KW':
484-
jwk.alg = require('internal/crypto/aes')
458+
parameters.alg = require('internal/crypto/aes')
485459
.getAlgorithmName(key.algorithm.name, key.algorithm.length);
486-
return jwk;
460+
break;
487461
case 'HMAC':
488-
jwk.alg = normalizeHashName(
462+
parameters.alg = normalizeHashName(
489463
key.algorithm.hash.name,
490464
normalizeHashName.kContextJwkHmac);
491-
return jwk;
465+
break;
492466
default:
493-
// Fall through
467+
return undefined;
494468
}
495469

496-
throw lazyDOMException('Not yet supported', 'NotSupportedError');
470+
return key[kKeyObject][kHandle].exportJwk(parameters, true);
497471
}
498472

499473
async function exportKey(format, key) {
@@ -511,17 +485,55 @@ async function exportKey(format, key) {
511485
context: '2nd argument',
512486
});
513487

488+
try {
489+
normalizeAlgorithm(key.algorithm, 'exportKey');
490+
} catch {
491+
throw lazyDOMException(
492+
`${key.algorithm.name} key export is not supported`, 'NotSupportedError');
493+
}
494+
514495
if (!key.extractable)
515496
throw lazyDOMException('key is not extractable', 'InvalidAccessException');
516497

498+
let result;
517499
switch (format) {
518-
case 'spki': return exportKeySpki(key);
519-
case 'pkcs8': return exportKeyPkcs8(key);
520-
case 'jwk': return exportKeyJWK(key);
521-
case 'raw': return exportKeyRaw(key);
500+
case 'spki': {
501+
if (key.type === 'public') {
502+
result = await exportKeySpki(key);
503+
}
504+
break;
505+
}
506+
case 'pkcs8': {
507+
if (key.type === 'private') {
508+
result = await exportKeyPkcs8(key);
509+
}
510+
break;
511+
}
512+
case 'jwk': {
513+
result = await exportKeyJWK(key);
514+
break;
515+
}
516+
case 'raw': {
517+
if (key.type === 'secret') {
518+
result = await exportKeyRawSecret(key);
519+
break;
520+
}
521+
522+
if (key.type === 'public') {
523+
result = await exportKeyRawPublic(key);
524+
break;
525+
}
526+
break;
527+
}
522528
}
523-
throw lazyDOMException(
524-
'Export format is unsupported', 'NotSupportedError');
529+
530+
if (!result) {
531+
throw lazyDOMException(
532+
`Unable to export ${key.algorithm.name} ${key.type} key using ${format} format`,
533+
'NotSupportedError');
534+
}
535+
536+
return result;
525537
}
526538

527539
async function importKey(
@@ -608,8 +620,12 @@ async function importKey(
608620
extractable,
609621
keyUsages);
610622
break;
611-
default:
612-
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
623+
}
624+
625+
if (!result) {
626+
throw lazyDOMException(
627+
`Unable to import ${algorithm.name} using ${format} format`,
628+
'NotSupportedError');
613629
}
614630

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

0 commit comments

Comments
 (0)