Skip to content

Commit 55e522c

Browse files
panvadanielleadams
authored andcommittedMar 16, 2021
crypto: support JWK objects in create*Key
PR-URL: #37254 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 4de3b84 commit 55e522c

File tree

4 files changed

+246
-56
lines changed

4 files changed

+246
-56
lines changed
 

‎doc/api/crypto.md

+17-8
Original file line numberDiff line numberDiff line change
@@ -2452,6 +2452,9 @@ input.on('readable', () => {
24522452
<!-- YAML
24532453
added: v11.6.0
24542454
changes:
2455+
- version: REPLACEME
2456+
pr-url: https://github.com/nodejs/node/pull/37254
2457+
description: The key can also be a JWK object.
24552458
- version: v15.0.0
24562459
pr-url: https://github.com/nodejs/node/pull/35093
24572460
description: The key can also be an ArrayBuffer. The encoding option was
@@ -2460,11 +2463,12 @@ changes:
24602463

24612464
<!--lint disable maximum-line-length remark-lint-->
24622465
* `key` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView}
2463-
* `key`: {string|ArrayBuffer|Buffer|TypedArray|DataView} The key material,
2464-
either in PEM or DER format.
2465-
* `format`: {string} Must be `'pem'` or `'der'`. **Default:** `'pem'`.
2466+
* `key`: {string|ArrayBuffer|Buffer|TypedArray|DataView|Object} The key
2467+
material, either in PEM, DER, or JWK format.
2468+
* `format`: {string} Must be `'pem'`, `'der'`, or '`'jwk'`.
2469+
**Default:** `'pem'`.
24662470
* `type`: {string} Must be `'pkcs1'`, `'pkcs8'` or `'sec1'`. This option is
2467-
required only if the `format` is `'der'` and ignored if it is `'pem'`.
2471+
required only if the `format` is `'der'` and ignored otherwise.
24682472
* `passphrase`: {string | Buffer} The passphrase to use for decryption.
24692473
* `encoding`: {string} The string encoding to use when `key` is a string.
24702474
* Returns: {KeyObject}
@@ -2481,6 +2485,9 @@ of the passphrase is limited to 1024 bytes.
24812485
<!-- YAML
24822486
added: v11.6.0
24832487
changes:
2488+
- version: REPLACEME
2489+
pr-url: https://github.com/nodejs/node/pull/37254
2490+
description: The key can also be a JWK object.
24842491
- version: v15.0.0
24852492
pr-url: https://github.com/nodejs/node/pull/35093
24862493
description: The key can also be an ArrayBuffer. The encoding option was
@@ -2496,10 +2503,12 @@ changes:
24962503

24972504
<!--lint disable maximum-line-length remark-lint-->
24982505
* `key` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView}
2499-
* `key`: {string|ArrayBuffer|Buffer|TypedArray|DataView}
2500-
* `format`: {string} Must be `'pem'` or `'der'`. **Default:** `'pem'`.
2501-
* `type`: {string} Must be `'pkcs1'` or `'spki'`. This option is required
2502-
only if the `format` is `'der'`.
2506+
* `key`: {string|ArrayBuffer|Buffer|TypedArray|DataView|Object} The key
2507+
material, either in PEM, DER, or JWK format.
2508+
* `format`: {string} Must be `'pem'`, `'der'`, or '`'jwk'`.
2509+
**Default:** `'pem'`.
2510+
* `type`: {string} Must be `'pkcs1'` or `'spki'`. This option is
2511+
required only if the `format` is `'der'` and ignored otherwise.
25032512
* `encoding` {string} The string encoding to use when `key` is a string.
25042513
* Returns: {KeyObject}
25052514
<!--lint enable maximum-line-length remark-lint-->

‎lib/internal/crypto/keys.js

+141-5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const {
2626
const {
2727
validateObject,
2828
validateOneOf,
29+
validateString,
2930
} = require('internal/validators');
3031

3132
const {
@@ -38,6 +39,7 @@ const {
3839
ERR_OPERATION_FAILED,
3940
ERR_CRYPTO_JWK_UNSUPPORTED_CURVE,
4041
ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE,
42+
ERR_CRYPTO_INVALID_JWK,
4143
}
4244
} = require('internal/errors');
4345

@@ -65,6 +67,8 @@ const {
6567

6668
const { inspect } = require('internal/util/inspect');
6769

70+
const { Buffer } = require('buffer');
71+
6872
const kAlgorithm = Symbol('kAlgorithm');
6973
const kExtractable = Symbol('kExtractable');
7074
const kKeyType = Symbol('kKeyType');
@@ -413,6 +417,122 @@ function getKeyTypes(allowKeyObject, bufferOnly = false) {
413417
return types;
414418
}
415419

420+
function getKeyObjectHandleFromJwk(key, ctx) {
421+
validateObject(key, 'key');
422+
validateOneOf(
423+
key.kty, 'key.kty', ['RSA', 'EC', 'OKP']);
424+
const isPublic = ctx === kConsumePublic || ctx === kCreatePublic;
425+
426+
if (key.kty === 'OKP') {
427+
validateString(key.crv, 'key.crv');
428+
validateOneOf(
429+
key.crv, 'key.crv', ['Ed25519', 'Ed448', 'X25519', 'X448']);
430+
validateString(key.x, 'key.x');
431+
432+
if (!isPublic)
433+
validateString(key.d, 'key.d');
434+
435+
let keyData;
436+
if (isPublic)
437+
keyData = Buffer.from(key.x, 'base64');
438+
else
439+
keyData = Buffer.from(key.d, 'base64');
440+
441+
switch (key.crv) {
442+
case 'Ed25519':
443+
case 'X25519':
444+
if (keyData.byteLength !== 32) {
445+
throw new ERR_CRYPTO_INVALID_JWK();
446+
}
447+
break;
448+
case 'Ed448':
449+
if (keyData.byteLength !== 57) {
450+
throw new ERR_CRYPTO_INVALID_JWK();
451+
}
452+
break;
453+
case 'X448':
454+
if (keyData.byteLength !== 56) {
455+
throw new ERR_CRYPTO_INVALID_JWK();
456+
}
457+
break;
458+
}
459+
460+
const handle = new KeyObjectHandle();
461+
if (isPublic) {
462+
handle.initEDRaw(
463+
`NODE-${key.crv.toUpperCase()}`,
464+
keyData,
465+
kKeyTypePublic);
466+
} else {
467+
handle.initEDRaw(
468+
`NODE-${key.crv.toUpperCase()}`,
469+
keyData,
470+
kKeyTypePrivate);
471+
}
472+
473+
return handle;
474+
}
475+
476+
if (key.kty === 'EC') {
477+
validateString(key.crv, 'key.crv');
478+
validateOneOf(
479+
key.crv, 'key.crv', ['P-256', 'secp256k1', 'P-384', 'P-521']);
480+
validateString(key.x, 'key.x');
481+
validateString(key.y, 'key.y');
482+
483+
const jwk = {
484+
kty: key.kty,
485+
crv: key.crv,
486+
x: key.x,
487+
y: key.y
488+
};
489+
490+
if (!isPublic) {
491+
validateString(key.d, 'key.d');
492+
jwk.d = key.d;
493+
}
494+
495+
const handle = new KeyObjectHandle();
496+
const type = handle.initJwk(jwk, jwk.crv);
497+
if (type === undefined)
498+
throw new ERR_CRYPTO_INVALID_JWK();
499+
500+
return handle;
501+
}
502+
503+
// RSA
504+
validateString(key.n, 'key.n');
505+
validateString(key.e, 'key.e');
506+
507+
const jwk = {
508+
kty: key.kty,
509+
n: key.n,
510+
e: key.e
511+
};
512+
513+
if (!isPublic) {
514+
validateString(key.d, 'key.d');
515+
validateString(key.p, 'key.p');
516+
validateString(key.q, 'key.q');
517+
validateString(key.dp, 'key.dp');
518+
validateString(key.dq, 'key.dq');
519+
validateString(key.qi, 'key.qi');
520+
jwk.d = key.d;
521+
jwk.p = key.p;
522+
jwk.q = key.q;
523+
jwk.dp = key.dp;
524+
jwk.dq = key.dq;
525+
jwk.qi = key.qi;
526+
}
527+
528+
const handle = new KeyObjectHandle();
529+
const type = handle.initJwk(jwk);
530+
if (type === undefined)
531+
throw new ERR_CRYPTO_INVALID_JWK();
532+
533+
return handle;
534+
}
535+
416536
function prepareAsymmetricKey(key, ctx) {
417537
if (isKeyObject(key)) {
418538
// Best case: A key object, as simple as that.
@@ -423,13 +543,15 @@ function prepareAsymmetricKey(key, ctx) {
423543
// Expect PEM by default, mostly for backward compatibility.
424544
return { format: kKeyFormatPEM, data: getArrayBufferOrView(key, 'key') };
425545
} else if (typeof key === 'object') {
426-
const { key: data, encoding } = key;
546+
const { key: data, encoding, format } = key;
427547
// The 'key' property can be a KeyObject as well to allow specifying
428548
// additional options such as padding along with the key.
429549
if (isKeyObject(data))
430550
return { data: getKeyObjectHandle(data, ctx) };
431551
else if (isCryptoKey(data))
432552
return { data: getKeyObjectHandle(data[kKeyObject], ctx) };
553+
else if (isJwk(data) && format === 'jwk')
554+
return { data: getKeyObjectHandleFromJwk(data, ctx), format: 'jwk' };
433555
// Either PEM or DER using PKCS#1 or SPKI.
434556
if (!isStringOrBuffer(data)) {
435557
throw new ERR_INVALID_ARG_TYPE(
@@ -494,16 +616,26 @@ function createSecretKey(key, encoding) {
494616
function createPublicKey(key) {
495617
const { format, type, data, passphrase } =
496618
prepareAsymmetricKey(key, kCreatePublic);
497-
const handle = new KeyObjectHandle();
498-
handle.init(kKeyTypePublic, data, format, type, passphrase);
619+
let handle;
620+
if (format === 'jwk') {
621+
handle = data;
622+
} else {
623+
handle = new KeyObjectHandle();
624+
handle.init(kKeyTypePublic, data, format, type, passphrase);
625+
}
499626
return new PublicKeyObject(handle);
500627
}
501628

502629
function createPrivateKey(key) {
503630
const { format, type, data, passphrase } =
504631
prepareAsymmetricKey(key, kCreatePrivate);
505-
const handle = new KeyObjectHandle();
506-
handle.init(kKeyTypePrivate, data, format, type, passphrase);
632+
let handle;
633+
if (format === 'jwk') {
634+
handle = data;
635+
} else {
636+
handle = new KeyObjectHandle();
637+
handle.init(kKeyTypePrivate, data, format, type, passphrase);
638+
}
507639
return new PrivateKeyObject(handle);
508640
}
509641

@@ -609,6 +741,10 @@ function isCryptoKey(obj) {
609741
return obj != null && obj[kKeyObject] !== undefined;
610742
}
611743

744+
function isJwk(obj) {
745+
return obj != null && obj.kty !== undefined;
746+
}
747+
612748
module.exports = {
613749
// Public API.
614750
createSecretKey,

‎lib/internal/errors.js

+1
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,7 @@ E('ERR_CRYPTO_INCOMPATIBLE_KEY', 'Incompatible %s: %s', Error);
836836
E('ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS', 'The selected key encoding %s %s.',
837837
Error);
838838
E('ERR_CRYPTO_INVALID_DIGEST', 'Invalid digest: %s', TypeError);
839+
E('ERR_CRYPTO_INVALID_JWK', 'Invalid JWK data', TypeError);
839840
E('ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE',
840841
'Invalid key object type %s, expected %s.', TypeError);
841842
E('ERR_CRYPTO_INVALID_STATE', 'Invalid state for operation %s', Error);

‎test/parallel/test-crypto-key-objects.js

+87-43
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,37 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
118118
}
119119

120120
{
121+
const jwk = {
122+
e: 'AQAB',
123+
n: 't9xYiIonscC3vz_A2ceR7KhZZlDu_5bye53nCVTcKnWd2seY6UAdKersX6njr83Dd5OVe' +
124+
'1BW_wJvp5EjWTAGYbFswlNmeD44edEGM939B6Lq-_8iBkrTi8mGN4YCytivE24YI0D4XZ' +
125+
'MPfkLSpab2y_Hy4DjQKBq1ThZ0UBnK-9IhX37Ju_ZoGYSlTIGIhzyaiYBh7wrZBoPczIE' +
126+
'u6et_kN2VnnbRUtkYTF97ggcv5h-hDpUQjQW0ZgOMcTc8n-RkGpIt0_iM_bTjI3Tz_gsF' +
127+
'di6hHcpZgbopPL630296iByyigQCPJVzdusFrQN5DeC-zT_nGypQkZanLb4ZspSx9Q',
128+
d: 'ktnq2LvIMqBj4txP82IEOorIRQGVsw1khbm8A-cEpuEkgM71Yi_0WzupKktucUeevQ5i0' +
129+
'Yh8w9e1SJiTLDRAlJz66kdky9uejiWWl6zR4dyNZVMFYRM43ijLC-P8rPne9Fz16IqHFW' +
130+
'5VbJqA1xCBhKmuPMsD71RNxZ4Hrsa7Kt_xglQTYsLbdGIwDmcZihId9VGXRzvmCPsDRf2' +
131+
'fCkAj7HDeRxpUdEiEDpajADc-PWikra3r3b40tVHKWm8wxJLivOIN7GiYXKQIW6RhZgH-' +
132+
'Rk45JIRNKxNagxdeXUqqyhnwhbTo1Hite0iBDexN9tgoZk0XmdYWBn6ElXHRZ7VCDQ',
133+
p: '8UovlB4nrBm7xH-u7XXBMbqxADQm5vaEZxw9eluc-tP7cIAI4sglMIvL_FMpbd2pEeP_B' +
134+
'kR76NTDzzDuPAZvUGRavgEjy0O9j2NAs_WPK4tZF-vFdunhnSh4EHAF4Ij9kbsUi90NOp' +
135+
'bGfVqPdOaHqzgHKoR23Cuusk9wFQ2XTV8',
136+
q: 'wxHdEYT9xrpfrHPqSBQPpO0dWGKJEkrWOb-76rSfuL8wGR4OBNmQdhLuU9zTIh22pog-X' +
137+
'PnLPAecC-4yu_wtJ2SPCKiKDbJBre0CKPyRfGqzvA3njXwMxXazU4kGs-2Fg-xu_iKbaI' +
138+
'jxXrclBLhkxhBtySrwAFhxxOk6fFcPLSs',
139+
dp: 'qS_Mdr5CMRGGMH0bKhPUWEtAixUGZhJaunX5wY71Xoc_Gh4cnO-b7BNJ_-5L8WZog0vr' +
140+
'6PgiLhrqBaCYm2wjpyoG2o2wDHm-NAlzN_wp3G2EFhrSxdOux-S1c0kpRcyoiAO2n29rN' +
141+
'Da-jOzwBBcU8ACEPdLOCQl0IEFFJO33tl8',
142+
dq: 'WAziKpxLKL7LnL4dzDcx8JIPIuwnTxh0plCDdCffyLaT8WJ9lXbXHFTjOvt8WfPrlDP_' +
143+
'Ylxmfkw5BbGZOP1VLGjZn2DkH9aMiwNmbDXFPdG0G3hzQovx_9fajiRV4DWghLHeT9wzJ' +
144+
'fZabRRiI0VQR472300AVEeX4vgbrDBn600',
145+
qi: 'k7czBCT9rHn_PNwCa17hlTy88C4vXkwbz83Oa-aX5L4e5gw5lhcR2ZuZHLb2r6oMt9rl' +
146+
'D7EIDItSs-u21LOXWPTAlazdnpYUyw_CzogM_PN-qNwMRXn5uXFFhmlP2mVg2EdELTahX' +
147+
'ch8kWqHaCSX53yvqCtRKu_j76V31TfQZGM',
148+
kty: 'RSA',
149+
};
150+
const publicJwk = { kty: jwk.kty, e: jwk.e, n: jwk.n };
151+
121152
const publicKey = createPublicKey(publicPem);
122153
assert.strictEqual(publicKey.type, 'public');
123154
assert.strictEqual(publicKey.asymmetricKeyType, 'rsa');
@@ -134,6 +165,16 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
134165
assert.strictEqual(derivedPublicKey.asymmetricKeyType, 'rsa');
135166
assert.strictEqual(derivedPublicKey.symmetricKeySize, undefined);
136167

168+
const publicKeyFromJwk = createPublicKey({ key: publicJwk, format: 'jwk' });
169+
assert.strictEqual(publicKey.type, 'public');
170+
assert.strictEqual(publicKey.asymmetricKeyType, 'rsa');
171+
assert.strictEqual(publicKey.symmetricKeySize, undefined);
172+
173+
const privateKeyFromJwk = createPrivateKey({ key: jwk, format: 'jwk' });
174+
assert.strictEqual(privateKey.type, 'private');
175+
assert.strictEqual(privateKey.asymmetricKeyType, 'rsa');
176+
assert.strictEqual(privateKey.symmetricKeySize, undefined);
177+
137178
// It should also be possible to import an encrypted private key as a public
138179
// key.
139180
const decryptedKey = createPublicKey({
@@ -158,46 +199,19 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
158199
});
159200
}
160201

161-
const jwk = {
162-
e: 'AQAB',
163-
n: 't9xYiIonscC3vz_A2ceR7KhZZlDu_5bye53nCVTcKnWd2seY6UAdKersX6njr83Dd5OVe' +
164-
'1BW_wJvp5EjWTAGYbFswlNmeD44edEGM939B6Lq-_8iBkrTi8mGN4YCytivE24YI0D4XZ' +
165-
'MPfkLSpab2y_Hy4DjQKBq1ThZ0UBnK-9IhX37Ju_ZoGYSlTIGIhzyaiYBh7wrZBoPczIE' +
166-
'u6et_kN2VnnbRUtkYTF97ggcv5h-hDpUQjQW0ZgOMcTc8n-RkGpIt0_iM_bTjI3Tz_gsF' +
167-
'di6hHcpZgbopPL630296iByyigQCPJVzdusFrQN5DeC-zT_nGypQkZanLb4ZspSx9Q',
168-
d: 'ktnq2LvIMqBj4txP82IEOorIRQGVsw1khbm8A-cEpuEkgM71Yi_0WzupKktucUeevQ5i0' +
169-
'Yh8w9e1SJiTLDRAlJz66kdky9uejiWWl6zR4dyNZVMFYRM43ijLC-P8rPne9Fz16IqHFW' +
170-
'5VbJqA1xCBhKmuPMsD71RNxZ4Hrsa7Kt_xglQTYsLbdGIwDmcZihId9VGXRzvmCPsDRf2' +
171-
'fCkAj7HDeRxpUdEiEDpajADc-PWikra3r3b40tVHKWm8wxJLivOIN7GiYXKQIW6RhZgH-' +
172-
'Rk45JIRNKxNagxdeXUqqyhnwhbTo1Hite0iBDexN9tgoZk0XmdYWBn6ElXHRZ7VCDQ',
173-
p: '8UovlB4nrBm7xH-u7XXBMbqxADQm5vaEZxw9eluc-tP7cIAI4sglMIvL_FMpbd2pEeP_B' +
174-
'kR76NTDzzDuPAZvUGRavgEjy0O9j2NAs_WPK4tZF-vFdunhnSh4EHAF4Ij9kbsUi90NOp' +
175-
'bGfVqPdOaHqzgHKoR23Cuusk9wFQ2XTV8',
176-
q: 'wxHdEYT9xrpfrHPqSBQPpO0dWGKJEkrWOb-76rSfuL8wGR4OBNmQdhLuU9zTIh22pog-X' +
177-
'PnLPAecC-4yu_wtJ2SPCKiKDbJBre0CKPyRfGqzvA3njXwMxXazU4kGs-2Fg-xu_iKbaI' +
178-
'jxXrclBLhkxhBtySrwAFhxxOk6fFcPLSs',
179-
dp: 'qS_Mdr5CMRGGMH0bKhPUWEtAixUGZhJaunX5wY71Xoc_Gh4cnO-b7BNJ_-5L8WZog0vr' +
180-
'6PgiLhrqBaCYm2wjpyoG2o2wDHm-NAlzN_wp3G2EFhrSxdOux-S1c0kpRcyoiAO2n29rN' +
181-
'Da-jOzwBBcU8ACEPdLOCQl0IEFFJO33tl8',
182-
dq: 'WAziKpxLKL7LnL4dzDcx8JIPIuwnTxh0plCDdCffyLaT8WJ9lXbXHFTjOvt8WfPrlDP_' +
183-
'Ylxmfkw5BbGZOP1VLGjZn2DkH9aMiwNmbDXFPdG0G3hzQovx_9fajiRV4DWghLHeT9wzJ' +
184-
'fZabRRiI0VQR472300AVEeX4vgbrDBn600',
185-
qi: 'k7czBCT9rHn_PNwCa17hlTy88C4vXkwbz83Oa-aX5L4e5gw5lhcR2ZuZHLb2r6oMt9rl' +
186-
'D7EIDItSs-u21LOXWPTAlazdnpYUyw_CzogM_PN-qNwMRXn5uXFFhmlP2mVg2EdELTahX' +
187-
'ch8kWqHaCSX53yvqCtRKu_j76V31TfQZGM',
188-
kty: 'RSA',
189-
};
190-
191-
for (const keyObject of [publicKey, derivedPublicKey]) {
202+
for (const keyObject of [publicKey, derivedPublicKey, publicKeyFromJwk]) {
192203
assert.deepStrictEqual(
193204
keyObject.export({ format: 'jwk' }),
194205
{ kty: 'RSA', n: jwk.n, e: jwk.e }
195206
);
196207
}
197-
assert.deepStrictEqual(
198-
privateKey.export({ format: 'jwk' }),
199-
jwk
200-
);
208+
209+
for (const keyObject of [privateKey, privateKeyFromJwk]) {
210+
assert.deepStrictEqual(
211+
keyObject.export({ format: 'jwk' }),
212+
jwk
213+
);
214+
}
201215

202216
// Exporting the key using JWK should not work since this format does not
203217
// support key encryption
@@ -235,10 +249,12 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
235249
// Encrypt using the public key.
236250
publicEncrypt(publicKey, plaintext),
237251
publicEncrypt({ key: publicKey }, plaintext),
252+
publicEncrypt({ key: publicJwk, format: 'jwk' }, plaintext),
238253

239254
// Encrypt using the private key.
240255
publicEncrypt(privateKey, plaintext),
241256
publicEncrypt({ key: privateKey }, plaintext),
257+
publicEncrypt({ key: jwk, format: 'jwk' }, plaintext),
242258

243259
// Encrypt using a public key derived from the private key.
244260
publicEncrypt(derivedPublicKey, plaintext),
@@ -251,7 +267,8 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
251267
], [
252268
privateKey,
253269
{ format: 'pem', key: privatePem },
254-
{ format: 'der', type: 'pkcs1', key: privateDER }
270+
{ format: 'der', type: 'pkcs1', key: privateDER },
271+
{ key: jwk, format: 'jwk' }
255272
]);
256273

257274
testDecryption(publicDecrypt, [
@@ -261,11 +278,13 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
261278
publicKey,
262279
{ format: 'pem', key: publicPem },
263280
{ format: 'der', type: 'pkcs1', key: publicDER },
281+
{ key: publicJwk, format: 'jwk' },
264282

265283
// Decrypt using the private key.
266284
privateKey,
267285
{ format: 'pem', key: privatePem },
268-
{ format: 'der', type: 'pkcs1', key: privateDER }
286+
{ format: 'der', type: 'pkcs1', key: privateDER },
287+
{ key: jwk, format: 'jwk' }
269288
]);
270289
}
271290

@@ -359,8 +378,20 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
359378
}
360379

361380
{
362-
[info.private, info.public].forEach((pem) => {
363-
const key = createPublicKey(pem);
381+
const key = createPrivateKey({ key: info.jwk, format: 'jwk' });
382+
assert.strictEqual(key.type, 'private');
383+
assert.strictEqual(key.asymmetricKeyType, keyType);
384+
assert.strictEqual(key.symmetricKeySize, undefined);
385+
assert.strictEqual(
386+
key.export({ type: 'pkcs8', format: 'pem' }), info.private);
387+
assert.deepStrictEqual(
388+
key.export({ format: 'jwk' }), info.jwk);
389+
}
390+
391+
{
392+
for (const input of [
393+
info.private, info.public, { key: info.jwk, format: 'jwk' }]) {
394+
const key = createPublicKey(input);
364395
assert.strictEqual(key.type, 'public');
365396
assert.strictEqual(key.asymmetricKeyType, keyType);
366397
assert.strictEqual(key.symmetricKeySize, undefined);
@@ -370,7 +401,7 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
370401
delete jwk.d;
371402
assert.deepStrictEqual(
372403
key.export({ format: 'jwk' }), jwk);
373-
});
404+
}
374405
}
375406
});
376407

@@ -438,8 +469,21 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
438469
}
439470

440471
{
441-
[info.private, info.public].forEach((pem) => {
442-
const key = createPublicKey(pem);
472+
const key = createPrivateKey({ key: info.jwk, format: 'jwk' });
473+
assert.strictEqual(key.type, 'private');
474+
assert.strictEqual(key.asymmetricKeyType, keyType);
475+
assert.deepStrictEqual(key.asymmetricKeyDetails, { namedCurve });
476+
assert.strictEqual(key.symmetricKeySize, undefined);
477+
assert.strictEqual(
478+
key.export({ type: 'pkcs8', format: 'pem' }), info.private);
479+
assert.deepStrictEqual(
480+
key.export({ format: 'jwk' }), info.jwk);
481+
}
482+
483+
{
484+
for (const input of [
485+
info.private, info.public, { key: info.jwk, format: 'jwk' }]) {
486+
const key = createPublicKey(input);
443487
assert.strictEqual(key.type, 'public');
444488
assert.strictEqual(key.asymmetricKeyType, keyType);
445489
assert.deepStrictEqual(key.asymmetricKeyDetails, { namedCurve });
@@ -450,7 +494,7 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
450494
delete jwk.d;
451495
assert.deepStrictEqual(
452496
key.export({ format: 'jwk' }), jwk);
453-
});
497+
}
454498
}
455499
});
456500

0 commit comments

Comments
 (0)
Please sign in to comment.