crypto: prepare webcrypto key import/export for modern algorithms · nodejs/node@a312e70

@@ -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

}

356345357346

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

}

395373396-

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

}

434411435412

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

}

490464491-

throw lazyDOMException('Not yet supported', 'NotSupportedError');

465+

return key[kKeyObject][kHandle].exportJwk(parameters, true);

492466

}

493467494468

async function exportKey(format, key) {

@@ -506,17 +480,55 @@ async function exportKey(format, key) {

506480

context: '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+509490

if (!key.extractable)

510491

throw lazyDOMException('key is not extractable', 'InvalidAccessException');

511492493+

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

}

521533522534

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

}

609625610626

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