Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit cbf6a01

Browse filesBrowse files
himself65targos
authored andcommitted
crypto: fix generateKeyPair with encoding 'jwk'
Fixes: #39205 PR-URL: #39319 Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 7a731ef commit cbf6a01
Copy full SHA for cbf6a01

8 files changed

+195-58Lines changed: 195 additions & 58 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎lib/internal/crypto/keygen.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/keygen.js
+4-1Lines changed: 4 additions & 1 deletion
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 {
@@ -60,7 +61,9 @@ const {
6061
const { isArrayBufferView } = require('internal/util/types');
6162

6263
function wrapKey(key, ctor) {
63-
if (typeof key === 'string' || isArrayBufferView(key))
64+
if (typeof key === 'string' ||
65+
isArrayBufferView(key) ||
66+
isJwk(key))
6467
return key;
6568
return new ctor(key);
6669
}
Collapse file

‎lib/internal/crypto/keys.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/keys.js
+10-31Lines changed: 10 additions & 31 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,
@@ -37,8 +38,6 @@ const {
3738
ERR_INVALID_ARG_VALUE,
3839
ERR_OUT_OF_RANGE,
3940
ERR_OPERATION_FAILED,
40-
ERR_CRYPTO_JWK_UNSUPPORTED_CURVE,
41-
ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE,
4241
ERR_CRYPTO_INVALID_JWK,
4342
}
4443
} = require('internal/errors');
@@ -151,7 +150,6 @@ const {
151150

152151
const kAsymmetricKeyType = Symbol('kAsymmetricKeyType');
153152
const kAsymmetricKeyDetails = Symbol('kAsymmetricKeyDetails');
154-
const kAsymmetricKeyJWKProperties = Symbol('kAsymmetricKeyJWKProperties');
155153

156154
function normalizeKeyDetails(details = {}) {
157155
if (details.publicExponent !== undefined) {
@@ -189,28 +187,6 @@ const {
189187
return {};
190188
}
191189
}
192-
193-
[kAsymmetricKeyJWKProperties]() {
194-
switch (this.asymmetricKeyType) {
195-
case 'rsa': return {};
196-
case 'ec':
197-
switch (this.asymmetricKeyDetails.namedCurve) {
198-
case 'prime256v1': return { crv: 'P-256' };
199-
case 'secp256k1': return { crv: 'secp256k1' };
200-
case 'secp384r1': return { crv: 'P-384' };
201-
case 'secp521r1': return { crv: 'P-521' };
202-
default:
203-
throw new ERR_CRYPTO_JWK_UNSUPPORTED_CURVE(
204-
this.asymmetricKeyDetails.namedCurve);
205-
}
206-
case 'ed25519': return { crv: 'Ed25519' };
207-
case 'ed448': return { crv: 'Ed448' };
208-
case 'x25519': return { crv: 'X25519' };
209-
case 'x448': return { crv: 'X448' };
210-
default:
211-
throw new ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE();
212-
}
213-
}
214190
}
215191

216192
class PublicKeyObject extends AsymmetricKeyObject {
@@ -220,8 +196,7 @@ const {
220196

221197
export(options) {
222198
if (options && options.format === 'jwk') {
223-
const properties = this[kAsymmetricKeyJWKProperties]();
224-
return this[kHandle].exportJwk(properties);
199+
return this[kHandle].exportJwk({});
225200
}
226201
const {
227202
format,
@@ -242,8 +217,7 @@ const {
242217
throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(
243218
'jwk', 'does not support encryption');
244219
}
245-
const properties = this[kAsymmetricKeyJWKProperties]();
246-
return this[kHandle].exportJwk(properties);
220+
return this[kHandle].exportJwk({});
247221
}
248222
const {
249223
format,
@@ -265,6 +239,8 @@ function parseKeyFormat(formatStr, defaultFormat, optionName) {
265239
return kKeyFormatPEM;
266240
else if (formatStr === 'der')
267241
return kKeyFormatDER;
242+
else if (formatStr === 'jwk')
243+
return kKeyFormatJWK;
268244
throw new ERR_INVALID_ARG_VALUE(optionName, formatStr);
269245
}
270246

@@ -305,12 +281,14 @@ function parseKeyFormatAndType(enc, keyType, isPublic, objName) {
305281
isInput ? kKeyFormatPEM : undefined,
306282
option('format', objName));
307283

284+
const isRequired = (!isInput ||
285+
format === kKeyFormatDER) &&
286+
format !== kKeyFormatJWK;
308287
const type = parseKeyType(typeStr,
309-
!isInput || format === kKeyFormatDER,
288+
isRequired,
310289
keyType,
311290
isPublic,
312291
option('type', objName));
313-
314292
return { format, type };
315293
}
316294

@@ -766,4 +744,5 @@ module.exports = {
766744
PrivateKeyObject,
767745
isKeyObject,
768746
isCryptoKey,
747+
isJwk,
769748
};
Collapse file

‎lib/internal/errors.js‎

Copy file name to clipboardExpand all lines: lib/internal/errors.js
-2Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -923,8 +923,6 @@ E('ERR_CRYPTO_INVALID_JWK', 'Invalid JWK data', TypeError);
923923
E('ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE',
924924
'Invalid key object type %s, expected %s.', TypeError);
925925
E('ERR_CRYPTO_INVALID_STATE', 'Invalid state for operation %s', Error);
926-
E('ERR_CRYPTO_JWK_UNSUPPORTED_CURVE', 'Unsupported JWK EC curve: %s.', Error);
927-
E('ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE', 'Unsupported JWK Key Type.', Error);
928926
E('ERR_CRYPTO_PBKDF2_ERROR', 'PBKDF2 error', Error);
929927
E('ERR_CRYPTO_SCRYPT_INVALID_PARAMETER', 'Invalid scrypt parameter', Error);
930928
E('ERR_CRYPTO_SCRYPT_NOT_SUPPORTED', 'Scrypt algorithm not supported', Error);
Collapse file

‎src/crypto/crypto_ec.cc‎

Copy file name to clipboardExpand all lines: src/crypto/crypto_ec.cc
+28Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,34 @@ Maybe<bool> ExportJWKEcKey(
740740
return Nothing<bool>();
741741
}
742742

743+
Local<String> crv_name;
744+
const int nid = EC_GROUP_get_curve_name(group);
745+
switch (nid) {
746+
case NID_X9_62_prime256v1:
747+
crv_name = OneByteString(env->isolate(), "P-256");
748+
break;
749+
case NID_secp256k1:
750+
crv_name = OneByteString(env->isolate(), "secp256k1");
751+
break;
752+
case NID_secp384r1:
753+
crv_name = OneByteString(env->isolate(), "P-384");
754+
break;
755+
case NID_secp521r1:
756+
crv_name = OneByteString(env->isolate(), "P-521");
757+
break;
758+
default: {
759+
THROW_ERR_CRYPTO_JWK_UNSUPPORTED_CURVE(
760+
env, "Unsupported JWK EC curve: %s.", OBJ_nid2sn(nid));
761+
return Nothing<bool>();
762+
}
763+
}
764+
if (target->Set(
765+
env->context(),
766+
env->jwk_crv_string(),
767+
crv_name).IsNothing()) {
768+
return Nothing<bool>();
769+
}
770+
743771
if (key->GetKeyType() == kKeyTypePrivate) {
744772
const BIGNUM* pvt = EC_KEY_get0_private_key(ec);
745773
return SetEncodedValue(
Collapse file

‎src/crypto/crypto_keys.cc‎

Copy file name to clipboardExpand all lines: src/crypto/crypto_keys.cc
+34-23Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@ void GetKeyFormatAndTypeFromJs(
6161
config->type_ = Just<PKEncodingType>(static_cast<PKEncodingType>(
6262
args[*offset + 1].As<Int32>()->Value()));
6363
} else {
64-
CHECK(context == kKeyContextInput && config->format_ == kKeyFormatPEM);
64+
CHECK(
65+
(context == kKeyContextInput &&
66+
config->format_ == kKeyFormatPEM) ||
67+
(context == kKeyContextGenerate &&
68+
config->format_ == kKeyFormatJWK));
6569
CHECK(args[*offset + 1]->IsNullOrUndefined());
6670
config->type_ = Nothing<PKEncodingType>();
6771
}
@@ -487,9 +491,7 @@ Maybe<bool> ExportJWKAsymmetricKey(
487491
std::shared_ptr<KeyObjectData> key,
488492
Local<Object> target) {
489493
switch (EVP_PKEY_id(key->GetAsymmetricKey().get())) {
490-
case EVP_PKEY_RSA:
491-
// Fall through
492-
case EVP_PKEY_RSA_PSS: return ExportJWKRsaKey(env, key, target);
494+
case EVP_PKEY_RSA: return ExportJWKRsaKey(env, key, target);
493495
case EVP_PKEY_EC: return ExportJWKEcKey(env, key, target);
494496
case EVP_PKEY_ED25519:
495497
// Fall through
@@ -499,7 +501,7 @@ Maybe<bool> ExportJWKAsymmetricKey(
499501
// Fall through
500502
case EVP_PKEY_X448: return ExportJWKEdKey(env, key, target);
501503
}
502-
THROW_ERR_CRYPTO_INVALID_KEYTYPE(env);
504+
THROW_ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE(env);
503505
return Just(false);
504506
}
505507

@@ -605,6 +607,21 @@ static inline Maybe<bool> Tristate(bool b) {
605607
return b ? Just(true) : Nothing<bool>();
606608
}
607609

610+
Maybe<bool> ExportJWKInner(Environment* env,
611+
std::shared_ptr<KeyObjectData> key,
612+
Local<Value> result) {
613+
switch (key->GetKeyType()) {
614+
case kKeyTypeSecret:
615+
return ExportJWKSecretKey(env, key, result.As<Object>());
616+
case kKeyTypePublic:
617+
// Fall through
618+
case kKeyTypePrivate:
619+
return ExportJWKAsymmetricKey(env, key, result.As<Object>());
620+
default:
621+
UNREACHABLE();
622+
}
623+
}
624+
608625
Maybe<bool> ManagedEVPPKey::ToEncodedPublicKey(
609626
Environment* env,
610627
ManagedEVPPKey key,
@@ -617,6 +634,11 @@ Maybe<bool> ManagedEVPPKey::ToEncodedPublicKey(
617634
std::shared_ptr<KeyObjectData> data =
618635
KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key));
619636
return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out));
637+
} else if (config.format_ == kKeyFormatJWK) {
638+
std::shared_ptr<KeyObjectData> data =
639+
KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key));
640+
*out = Object::New(env->isolate());
641+
return ExportJWKInner(env, data, *out);
620642
}
621643

622644
return Tristate(WritePublicKey(env, key.get(), config).ToLocal(out));
@@ -632,6 +654,11 @@ Maybe<bool> ManagedEVPPKey::ToEncodedPrivateKey(
632654
std::shared_ptr<KeyObjectData> data =
633655
KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key));
634656
return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out));
657+
} else if (config.format_ == kKeyFormatJWK) {
658+
std::shared_ptr<KeyObjectData> data =
659+
KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key));
660+
*out = Object::New(env->isolate());
661+
return ExportJWKInner(env, data, *out);
635662
}
636663

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

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

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-
}
1241+
ExportJWKInner(env, key->Data(), args[0]);
12321242

12331243
args.GetReturnValue().Set(args[0]);
12341244
}
@@ -1380,6 +1390,7 @@ void Initialize(Environment* env, Local<Object> target) {
13801390
NODE_DEFINE_CONSTANT(target, kKeyEncodingSEC1);
13811391
NODE_DEFINE_CONSTANT(target, kKeyFormatDER);
13821392
NODE_DEFINE_CONSTANT(target, kKeyFormatPEM);
1393+
NODE_DEFINE_CONSTANT(target, kKeyFormatJWK);
13831394
NODE_DEFINE_CONSTANT(target, kKeyTypeSecret);
13841395
NODE_DEFINE_CONSTANT(target, kKeyTypePublic);
13851396
NODE_DEFINE_CONSTANT(target, kKeyTypePrivate);
Collapse file

‎src/crypto/crypto_keys.h‎

Copy file name to clipboardExpand all lines: src/crypto/crypto_keys.h
+2-1Lines 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 {
Collapse file

‎src/node_errors.h‎

Copy file name to clipboardExpand all lines: src/node_errors.h
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ void OnFatalError(const char* location, const char* message);
4949
V(ERR_CRYPTO_INVALID_SCRYPT_PARAMS, RangeError) \
5050
V(ERR_CRYPTO_INVALID_STATE, Error) \
5151
V(ERR_CRYPTO_INVALID_TAG_LENGTH, RangeError) \
52+
V(ERR_CRYPTO_JWK_UNSUPPORTED_CURVE, Error) \
53+
V(ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE, Error) \
5254
V(ERR_CRYPTO_OPERATION_FAILED, Error) \
5355
V(ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH, RangeError) \
5456
V(ERR_CRYPTO_UNKNOWN_CIPHER, Error) \
@@ -136,6 +138,7 @@ ERRORS_WITH_CODE(V)
136138
V(ERR_CRYPTO_INVALID_SCRYPT_PARAMS, "Invalid scrypt params") \
137139
V(ERR_CRYPTO_INVALID_STATE, "Invalid state") \
138140
V(ERR_CRYPTO_INVALID_TAG_LENGTH, "Invalid taglength") \
141+
V(ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE, "Unsupported JWK Key Type.") \
139142
V(ERR_CRYPTO_OPERATION_FAILED, "Operation failed") \
140143
V(ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH, \
141144
"Input buffers must have the same byte length") \

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.