Skip to content

Commit 201f541

Browse files
committed
crypto: prepare webcrypto key export code for modern algorithms
1 parent a93da0a commit 201f541

File tree

2 files changed

+94
-79
lines changed

2 files changed

+94
-79
lines changed

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: 78 additions & 79 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,43 @@ 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

396374
async function exportKeyRaw(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);
418390
case 'AES-CTR':
419391
// Fall through
420392
case 'AES-CBC':
@@ -425,70 +397,65 @@ async function exportKeyRaw(key) {
425397
// Fall through
426398
case 'HMAC':
427399
return key[kKeyObject].export().buffer;
400+
default:
401+
return undefined;
428402
}
429-
430-
throw lazyDOMException(
431-
`Unable to export a raw ${key.algorithm.name} ${key.type} key`,
432-
'InvalidAccessError');
433403
}
434404

435405
async function exportKeyJWK(key) {
436-
const jwk = key[kKeyObject][kHandle].exportJwk({
406+
const parameters = {
437407
key_ops: key.usages,
438408
ext: key.extractable,
439-
}, true);
409+
};
440410
switch (key.algorithm.name) {
441411
case 'RSASSA-PKCS1-v1_5':
442-
jwk.alg = normalizeHashName(
412+
parameters.alg = normalizeHashName(
443413
key.algorithm.hash.name,
444414
normalizeHashName.kContextJwkRsa);
445-
return jwk;
415+
break;
446416
case 'RSA-PSS':
447-
jwk.alg = normalizeHashName(
417+
parameters.alg = normalizeHashName(
448418
key.algorithm.hash.name,
449419
normalizeHashName.kContextJwkRsaPss);
450-
return jwk;
420+
break;
451421
case 'RSA-OAEP':
452-
jwk.alg = normalizeHashName(
422+
parameters.alg = normalizeHashName(
453423
key.algorithm.hash.name,
454424
normalizeHashName.kContextJwkRsaOaep);
455-
return jwk;
425+
break;
456426
case 'ECDSA':
457427
// Fall through
458428
case 'ECDH':
459-
jwk.crv ||= key.algorithm.namedCurve;
460-
return jwk;
429+
// Fall through
461430
case 'X25519':
462431
// Fall through
463432
case 'X448':
464-
jwk.crv ||= key.algorithm.name;
465-
return jwk;
433+
break;
466434
case 'Ed25519':
467435
// Fall through
468436
case 'Ed448':
469-
jwk.crv ||= key.algorithm.name;
470-
jwk.alg = key.algorithm.name;
471-
return jwk;
437+
parameters.alg = key.algorithm.name;
438+
break;
472439
case 'AES-CTR':
473440
// Fall through
474441
case 'AES-CBC':
475442
// Fall through
476443
case 'AES-GCM':
477444
// Fall through
478445
case 'AES-KW':
479-
jwk.alg = require('internal/crypto/aes')
446+
parameters.alg = require('internal/crypto/aes')
480447
.getAlgorithmName(key.algorithm.name, key.algorithm.length);
481-
return jwk;
448+
break;
482449
case 'HMAC':
483-
jwk.alg = normalizeHashName(
450+
parameters.alg = normalizeHashName(
484451
key.algorithm.hash.name,
485452
normalizeHashName.kContextJwkHmac);
486-
return jwk;
453+
break;
487454
default:
488-
// Fall through
455+
return undefined;
489456
}
490457

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

494461
async function exportKey(format, key) {
@@ -506,17 +473,49 @@ async function exportKey(format, key) {
506473
context: '2nd argument',
507474
});
508475

476+
try {
477+
normalizeAlgorithm(key.algorithm, 'exportKey');
478+
} catch {
479+
throw lazyDOMException(
480+
`${key.algorithm.name} key export is not supported`, 'NotSupportedError');
481+
}
482+
509483
if (!key.extractable)
510484
throw lazyDOMException('key is not extractable', 'InvalidAccessException');
511485

486+
let result;
512487
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);
488+
case 'spki': {
489+
if (key.type === 'public') {
490+
result = await exportKeySpki(key);
491+
}
492+
break;
493+
}
494+
case 'pkcs8': {
495+
if (key.type === 'private') {
496+
result = await exportKeyPkcs8(key);
497+
}
498+
break;
499+
}
500+
case 'jwk': {
501+
result = await exportKeyJWK(key);
502+
break;
503+
}
504+
case 'raw': {
505+
if (key.type !== 'private') {
506+
result = await exportKeyRaw(key);
507+
}
508+
break;
509+
}
510+
}
511+
512+
if (!result) {
513+
throw lazyDOMException(
514+
`Unable to export ${key.algorithm.name} ${key.type} key using ${format} format`,
515+
'NotSupportedError');
517516
}
518-
throw lazyDOMException(
519-
'Export format is unsupported', 'NotSupportedError');
517+
518+
return result;
520519
}
521520

522521
async function importKey(

0 commit comments

Comments
 (0)