Skip to content

Commit 8050957

Browse files
committed
crypto: fix generateKeyPair with encoding 'jwk'
Fixes: #39205
1 parent 80e7872 commit 8050957

File tree

5 files changed

+56
-19
lines changed

5 files changed

+56
-19
lines changed

lib/internal/crypto/keygen.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const {
3131
SecretKeyObject,
3232
parsePublicKeyEncoding,
3333
parsePrivateKeyEncoding,
34+
isJwk
3435
} = require('internal/crypto/keys');
3536

3637
const {
@@ -62,6 +63,9 @@ const { isArrayBufferView } = require('internal/util/types');
6263
function wrapKey(key, ctor) {
6364
if (typeof key === 'string' || isArrayBufferView(key))
6465
return key;
66+
else if (isJwk(key)) {
67+
return key;
68+
}
6569
return new ctor(key);
6670
}
6771

lib/internal/crypto/keys.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const {
1717
kKeyTypePrivate,
1818
kKeyFormatPEM,
1919
kKeyFormatDER,
20+
kKeyFormatJWK,
2021
kKeyEncodingPKCS1,
2122
kKeyEncodingPKCS8,
2223
kKeyEncodingSPKI,
@@ -265,6 +266,8 @@ function parseKeyFormat(formatStr, defaultFormat, optionName) {
265266
return kKeyFormatPEM;
266267
else if (formatStr === 'der')
267268
return kKeyFormatDER;
269+
else if (formatStr === 'jwk')
270+
return kKeyFormatJWK;
268271
throw new ERR_INVALID_ARG_VALUE(optionName, formatStr);
269272
}
270273

@@ -766,4 +769,5 @@ module.exports = {
766769
PrivateKeyObject,
767770
isKeyObject,
768771
isCryptoKey,
772+
isJwk,
769773
};

src/crypto/crypto_keys.cc

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,21 @@ static inline Maybe<bool> Tristate(bool b) {
605605
return b ? Just(true) : Nothing<bool>();
606606
}
607607

608+
Maybe<bool> ExportJWKInner(Environment* env,
609+
std::shared_ptr<KeyObjectData> key,
610+
Local<Value> result) {
611+
switch (key->GetKeyType()) {
612+
case kKeyTypeSecret:
613+
return ExportJWKSecretKey(env, key, result.As<Object>());
614+
case kKeyTypePublic:
615+
// Fall through
616+
case kKeyTypePrivate:
617+
return ExportJWKAsymmetricKey(env, key, result.As<Object>());
618+
default:
619+
UNREACHABLE();
620+
}
621+
}
622+
608623
Maybe<bool> ManagedEVPPKey::ToEncodedPublicKey(
609624
Environment* env,
610625
ManagedEVPPKey key,
@@ -617,6 +632,11 @@ Maybe<bool> ManagedEVPPKey::ToEncodedPublicKey(
617632
std::shared_ptr<KeyObjectData> data =
618633
KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key));
619634
return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out));
635+
} else if (config.format_ == kKeyFormatJWK) {
636+
std::shared_ptr<KeyObjectData> data =
637+
KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key));
638+
*out = Object::New(env->isolate());
639+
return ExportJWKInner(env, data, *out);
620640
}
621641

622642
return Tristate(WritePublicKey(env, key.get(), config).ToLocal(out));
@@ -632,6 +652,11 @@ Maybe<bool> ManagedEVPPKey::ToEncodedPrivateKey(
632652
std::shared_ptr<KeyObjectData> data =
633653
KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key));
634654
return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out));
655+
} else if (config.format_ == kKeyFormatJWK) {
656+
std::shared_ptr<KeyObjectData> data =
657+
KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key));
658+
*out = Object::New(env->isolate());
659+
return ExportJWKInner(env, data, *out);
635660
}
636661

637662
return Tristate(WritePrivateKey(env, key.get(), config).ToLocal(out));
@@ -1211,24 +1236,7 @@ void KeyObjectHandle::ExportJWK(
12111236

12121237
CHECK(args[0]->IsObject());
12131238

1214-
switch (key->Data()->GetKeyType()) {
1215-
case kKeyTypeSecret:
1216-
if (ExportJWKSecretKey(env, key->Data(), args[0].As<Object>())
1217-
.IsNothing()) {
1218-
return;
1219-
}
1220-
break;
1221-
case kKeyTypePublic:
1222-
// Fall through
1223-
case kKeyTypePrivate:
1224-
if (ExportJWKAsymmetricKey(env, key->Data(), args[0].As<Object>())
1225-
.IsNothing()) {
1226-
return;
1227-
}
1228-
break;
1229-
default:
1230-
UNREACHABLE();
1231-
}
1239+
ExportJWKInner(env, key->Data(), args[0]);
12321240

12331241
args.GetReturnValue().Set(args[0]);
12341242
}
@@ -1380,6 +1388,7 @@ void Initialize(Environment* env, Local<Object> target) {
13801388
NODE_DEFINE_CONSTANT(target, kKeyEncodingSEC1);
13811389
NODE_DEFINE_CONSTANT(target, kKeyFormatDER);
13821390
NODE_DEFINE_CONSTANT(target, kKeyFormatPEM);
1391+
NODE_DEFINE_CONSTANT(target, kKeyFormatJWK);
13831392
NODE_DEFINE_CONSTANT(target, kKeyTypeSecret);
13841393
NODE_DEFINE_CONSTANT(target, kKeyTypePublic);
13851394
NODE_DEFINE_CONSTANT(target, kKeyTypePrivate);

src/crypto/crypto_keys.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ enum PKEncodingType {
3131

3232
enum PKFormatType {
3333
kKeyFormatDER,
34-
kKeyFormatPEM
34+
kKeyFormatPEM,
35+
kKeyFormatJWK
3536
};
3637

3738
enum KeyType {

test/parallel/test-crypto-keygen.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,25 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
603603
passphrase: 'top secret'
604604
});
605605
}));
606+
607+
// Test async elliptic curve key generation with 'jwk' encoding
608+
generateKeyPair('ec', {
609+
namedCurve: "P-384",
610+
publicKeyEncoding: {
611+
type: 'spki',
612+
format: 'jwk'
613+
},
614+
privateKeyEncoding: {
615+
type: 'pkcs8',
616+
format: 'jwk'
617+
}
618+
}, common.mustSucceed((publicKey, privateKey) => {
619+
assert.strictEqual(typeof publicKey, 'object')
620+
assert.strictEqual(typeof privateKey, 'object')
621+
assert.strictEqual(publicKey.x, privateKey.x)
622+
assert.strictEqual(publicKey.y, privateKey.y)
623+
assert.strictEqual(publicKey.kty, privateKey.kty)
624+
}));
606625
}
607626

608627
// Test invalid parameter encoding.

0 commit comments

Comments
 (0)