Skip to content

Commit

Permalink
crypto: fix generateKeyPair with encoding 'jwk'
Browse files Browse the repository at this point in the history
Fixes: #39205
  • Loading branch information
himself65 committed Jul 9, 2021
1 parent 80e7872 commit 68df3f7
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 19 deletions.
4 changes: 4 additions & 0 deletions lib/internal/crypto/keygen.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const {
SecretKeyObject,
parsePublicKeyEncoding,
parsePrivateKeyEncoding,
isJwk
} = require('internal/crypto/keys');

const {
Expand Down Expand Up @@ -62,6 +63,9 @@ const { isArrayBufferView } = require('internal/util/types');
function wrapKey(key, ctor) {
if (typeof key === 'string' || isArrayBufferView(key))
return key;
else if (isJwk(key)) {
return key;
}
return new ctor(key);
}

Expand Down
4 changes: 4 additions & 0 deletions lib/internal/crypto/keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const {
kKeyTypePrivate,
kKeyFormatPEM,
kKeyFormatDER,
kKeyFormatJWK,
kKeyEncodingPKCS1,
kKeyEncodingPKCS8,
kKeyEncodingSPKI,
Expand Down Expand Up @@ -265,6 +266,8 @@ function parseKeyFormat(formatStr, defaultFormat, optionName) {
return kKeyFormatPEM;
else if (formatStr === 'der')
return kKeyFormatDER;
else if (formatStr === 'jwk')
return kKeyFormatJWK;
throw new ERR_INVALID_ARG_VALUE(optionName, formatStr);
}

Expand Down Expand Up @@ -766,4 +769,5 @@ module.exports = {
PrivateKeyObject,
isKeyObject,
isCryptoKey,
isJwk,
};
45 changes: 27 additions & 18 deletions src/crypto/crypto_keys.cc
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,21 @@ static inline Maybe<bool> Tristate(bool b) {
return b ? Just(true) : Nothing<bool>();
}

Maybe<bool> ExportJWKInner(Environment* env,
std::shared_ptr<KeyObjectData> key,
Local<Value> result) {
switch (key->GetKeyType()) {
case kKeyTypeSecret:
return ExportJWKSecretKey(env, key, result.As<Object>());
case kKeyTypePublic:
// Fall through
case kKeyTypePrivate:
return ExportJWKAsymmetricKey(env, key, result.As<Object>());
default:
UNREACHABLE();
}
}

Maybe<bool> ManagedEVPPKey::ToEncodedPublicKey(
Environment* env,
ManagedEVPPKey key,
Expand All @@ -617,6 +632,11 @@ Maybe<bool> ManagedEVPPKey::ToEncodedPublicKey(
std::shared_ptr<KeyObjectData> data =
KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key));
return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out));
} else if (config.format_ == kKeyFormatJWK) {
std::shared_ptr<KeyObjectData> data =
KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key));
*out = Object::New(env->isolate());
return ExportJWKInner(env, data, *out);
}

return Tristate(WritePublicKey(env, key.get(), config).ToLocal(out));
Expand All @@ -632,6 +652,11 @@ Maybe<bool> ManagedEVPPKey::ToEncodedPrivateKey(
std::shared_ptr<KeyObjectData> data =
KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key));
return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out));
} else if (config.format_ == kKeyFormatJWK) {
std::shared_ptr<KeyObjectData> data =
KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key));
*out = Object::New(env->isolate());
return ExportJWKInner(env, data, *out);
}

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

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

switch (key->Data()->GetKeyType()) {
case kKeyTypeSecret:
if (ExportJWKSecretKey(env, key->Data(), args[0].As<Object>())
.IsNothing()) {
return;
}
break;
case kKeyTypePublic:
// Fall through
case kKeyTypePrivate:
if (ExportJWKAsymmetricKey(env, key->Data(), args[0].As<Object>())
.IsNothing()) {
return;
}
break;
default:
UNREACHABLE();
}
ExportJWKInner(env, key->Data(), args[0]);

args.GetReturnValue().Set(args[0]);
}
Expand Down Expand Up @@ -1380,6 +1388,7 @@ void Initialize(Environment* env, Local<Object> target) {
NODE_DEFINE_CONSTANT(target, kKeyEncodingSEC1);
NODE_DEFINE_CONSTANT(target, kKeyFormatDER);
NODE_DEFINE_CONSTANT(target, kKeyFormatPEM);
NODE_DEFINE_CONSTANT(target, kKeyFormatJWK);
NODE_DEFINE_CONSTANT(target, kKeyTypeSecret);
NODE_DEFINE_CONSTANT(target, kKeyTypePublic);
NODE_DEFINE_CONSTANT(target, kKeyTypePrivate);
Expand Down
3 changes: 2 additions & 1 deletion src/crypto/crypto_keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ enum PKEncodingType {

enum PKFormatType {
kKeyFormatDER,
kKeyFormatPEM
kKeyFormatPEM,
kKeyFormatJWK
};

enum KeyType {
Expand Down
19 changes: 19 additions & 0 deletions test/parallel/test-crypto-keygen.js
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,25 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
passphrase: 'top secret'
});
}));

// Test async elliptic curve key generation with 'jwk' encoding
generateKeyPair('ec', {
namedCurve: 'P-384',
publicKeyEncoding: {
type: 'spki',
format: 'jwk'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'jwk'
}
}, common.mustSucceed((publicKey, privateKey) => {
assert.strictEqual(typeof publicKey, 'object');
assert.strictEqual(typeof privateKey, 'object');
assert.strictEqual(publicKey.x, privateKey.x);
assert.strictEqual(publicKey.y, privateKey.y);
assert.strictEqual(publicKey.kty, privateKey.kty);
}));
}

// Test invalid parameter encoding.
Expand Down

0 comments on commit 68df3f7

Please sign in to comment.