From 032bb15b367f4598634761b64678d575f328fb39 Mon Sep 17 00:00:00 2001 From: himself65 Date: Fri, 9 Jul 2021 12:07:32 +0800 Subject: [PATCH 01/17] crypto: fix `generateKeyPair` with encoding 'jwk' Fixes: https://github.com/nodejs/node/issues/39205 --- lib/internal/crypto/keygen.js | 4 +++ lib/internal/crypto/keys.js | 4 +++ src/crypto/crypto_keys.cc | 45 +++++++++++++++++------------ src/crypto/crypto_keys.h | 3 +- test/parallel/test-crypto-keygen.js | 19 ++++++++++++ 5 files changed, 56 insertions(+), 19 deletions(-) diff --git a/lib/internal/crypto/keygen.js b/lib/internal/crypto/keygen.js index 06490e24a9c24f..16d9e9d3e81663 100644 --- a/lib/internal/crypto/keygen.js +++ b/lib/internal/crypto/keygen.js @@ -31,6 +31,7 @@ const { SecretKeyObject, parsePublicKeyEncoding, parsePrivateKeyEncoding, + isJwk } = require('internal/crypto/keys'); const { @@ -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); } diff --git a/lib/internal/crypto/keys.js b/lib/internal/crypto/keys.js index c24b2d14eb5001..c0336927bdd99a 100644 --- a/lib/internal/crypto/keys.js +++ b/lib/internal/crypto/keys.js @@ -17,6 +17,7 @@ const { kKeyTypePrivate, kKeyFormatPEM, kKeyFormatDER, + kKeyFormatJWK, kKeyEncodingPKCS1, kKeyEncodingPKCS8, kKeyEncodingSPKI, @@ -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); } @@ -766,4 +769,5 @@ module.exports = { PrivateKeyObject, isKeyObject, isCryptoKey, + isJwk, }; diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc index 21cc988cee6a18..e048a82e451613 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc @@ -605,6 +605,21 @@ static inline Maybe Tristate(bool b) { return b ? Just(true) : Nothing(); } +Maybe ExportJWKInner(Environment* env, + std::shared_ptr key, + Local result) { + switch (key->GetKeyType()) { + case kKeyTypeSecret: + return ExportJWKSecretKey(env, key, result.As()); + case kKeyTypePublic: + // Fall through + case kKeyTypePrivate: + return ExportJWKAsymmetricKey(env, key, result.As()); + default: + UNREACHABLE(); + } +} + Maybe ManagedEVPPKey::ToEncodedPublicKey( Environment* env, ManagedEVPPKey key, @@ -617,6 +632,11 @@ Maybe ManagedEVPPKey::ToEncodedPublicKey( std::shared_ptr data = KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key)); return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out)); + } else if (config.format_ == kKeyFormatJWK) { + std::shared_ptr 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)); @@ -632,6 +652,11 @@ Maybe ManagedEVPPKey::ToEncodedPrivateKey( std::shared_ptr data = KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key)); return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out)); + } else if (config.format_ == kKeyFormatJWK) { + std::shared_ptr 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)); @@ -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()) - .IsNothing()) { - return; - } - break; - case kKeyTypePublic: - // Fall through - case kKeyTypePrivate: - if (ExportJWKAsymmetricKey(env, key->Data(), args[0].As()) - .IsNothing()) { - return; - } - break; - default: - UNREACHABLE(); - } + ExportJWKInner(env, key->Data(), args[0]); args.GetReturnValue().Set(args[0]); } @@ -1380,6 +1388,7 @@ void Initialize(Environment* env, Local 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); diff --git a/src/crypto/crypto_keys.h b/src/crypto/crypto_keys.h index 3662b3a3b8688b..df3ab8ab181437 100644 --- a/src/crypto/crypto_keys.h +++ b/src/crypto/crypto_keys.h @@ -31,7 +31,8 @@ enum PKEncodingType { enum PKFormatType { kKeyFormatDER, - kKeyFormatPEM + kKeyFormatPEM, + kKeyFormatJWK }; enum KeyType { diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index 4612fc4a1ac40a..f18e82b530314e 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -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. From edcc4c17942d1240da50837861a6e5f71497795d Mon Sep 17 00:00:00 2001 From: Himself65 Date: Fri, 9 Jul 2021 14:35:25 +0800 Subject: [PATCH 02/17] fixup!: Update lib/internal/crypto/keygen.js Co-authored-by: Voltrex --- lib/internal/crypto/keygen.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/internal/crypto/keygen.js b/lib/internal/crypto/keygen.js index 16d9e9d3e81663..2832a7b43c9d81 100644 --- a/lib/internal/crypto/keygen.js +++ b/lib/internal/crypto/keygen.js @@ -61,11 +61,10 @@ const { const { isArrayBufferView } = require('internal/util/types'); function wrapKey(key, ctor) { - if (typeof key === 'string' || isArrayBufferView(key)) - return key; - else if (isJwk(key)) { - return key; - } + if (typeof key === 'string' || + isArrayBufferView(key) || + isJwk(key)) + return key; return new ctor(key); } From 5a204974f8e5c12d7feb53e71cabebd00a31b8e8 Mon Sep 17 00:00:00 2001 From: Himself65 Date: Fri, 9 Jul 2021 14:55:39 +0800 Subject: [PATCH 03/17] fixup!: Update lib/internal/crypto/keygen.js Co-authored-by: Voltrex --- lib/internal/crypto/keygen.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/internal/crypto/keygen.js b/lib/internal/crypto/keygen.js index 2832a7b43c9d81..49a7f044cb66cd 100644 --- a/lib/internal/crypto/keygen.js +++ b/lib/internal/crypto/keygen.js @@ -61,10 +61,10 @@ const { const { isArrayBufferView } = require('internal/util/types'); function wrapKey(key, ctor) { - if (typeof key === 'string' || - isArrayBufferView(key) || - isJwk(key)) - return key; + if (typeof key === 'string' || + isArrayBufferView(key) || + isJwk(key)) + return key; return new ctor(key); } From f81c8594ace5c1d0da1670c6d9624d706e4b0075 Mon Sep 17 00:00:00 2001 From: Himself65 Date: Mon, 12 Jul 2021 11:11:13 +0800 Subject: [PATCH 04/17] fixup!: Update test/parallel/test-crypto-keygen.js Co-authored-by: Filip Skokan --- test/parallel/test-crypto-keygen.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index f18e82b530314e..57ad087902d6e2 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -620,7 +620,12 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); assert.strictEqual(typeof privateKey, 'object'); assert.strictEqual(publicKey.x, privateKey.x); assert.strictEqual(publicKey.y, privateKey.y); + assert(!publicKey.d); + assert(privateKey.d); + assert.strictEqual(publicKey.kty, 'EC'); assert.strictEqual(publicKey.kty, privateKey.kty); + assert.strictEqual(publicKey.crv, 'P-384'); + assert.strictEqual(publicKey.crv, privateKey.crv); })); } From 5d0b081dd765e37039e7eece29e1e5a548aefdab Mon Sep 17 00:00:00 2001 From: Himself65 Date: Mon, 12 Jul 2021 11:11:25 +0800 Subject: [PATCH 05/17] fixup!: Update test/parallel/test-crypto-keygen.js Co-authored-by: Filip Skokan --- test/parallel/test-crypto-keygen.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index 57ad087902d6e2..490886203823a1 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -608,11 +608,9 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); generateKeyPair('ec', { namedCurve: 'P-384', publicKeyEncoding: { - type: 'spki', format: 'jwk' }, privateKeyEncoding: { - type: 'pkcs8', format: 'jwk' } }, common.mustSucceed((publicKey, privateKey) => { From a5672f111a0f887bc62e2eea89989bdc136cc34b Mon Sep 17 00:00:00 2001 From: himself65 Date: Mon, 19 Jul 2021 14:05:20 +0800 Subject: [PATCH 06/17] fixup!: passing format 'jwk' --- lib/internal/crypto/keys.js | 6 ++++-- src/crypto/crypto_keys.cc | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/internal/crypto/keys.js b/lib/internal/crypto/keys.js index c0336927bdd99a..41698e5f02939e 100644 --- a/lib/internal/crypto/keys.js +++ b/lib/internal/crypto/keys.js @@ -308,12 +308,14 @@ function parseKeyFormatAndType(enc, keyType, isPublic, objName) { isInput ? kKeyFormatPEM : undefined, option('format', objName)); + const isRequired = (!isInput || + format === kKeyFormatDER) && + format !== kKeyFormatJWK; const type = parseKeyType(typeStr, - !isInput || format === kKeyFormatDER, + isRequired, keyType, isPublic, option('type', objName)); - return { format, type }; } diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc index e048a82e451613..89ad0874e0ffb9 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc @@ -61,7 +61,10 @@ void GetKeyFormatAndTypeFromJs( config->type_ = Just(static_cast( args[*offset + 1].As()->Value())); } else { - CHECK(context == kKeyContextInput && config->format_ == kKeyFormatPEM); + CHECK( + (context == kKeyContextInput && config->format_ == kKeyFormatPEM) || + (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK) + ); CHECK(args[*offset + 1]->IsNullOrUndefined()); config->type_ = Nothing(); } From 95bd164a9bad1fc2b690e204e7b2a57ed78b1a2f Mon Sep 17 00:00:00 2001 From: himself65 Date: Mon, 19 Jul 2021 15:38:22 +0800 Subject: [PATCH 07/17] fixup!: move crv_name check to c++ part --- lib/internal/crypto/keys.js | 29 ++--------------------------- lib/internal/errors.js | 1 - src/crypto/crypto_ec.cc | 27 +++++++++++++++++++++++++++ src/crypto/crypto_keys.cc | 2 ++ src/node_errors.h | 3 +++ 5 files changed, 34 insertions(+), 28 deletions(-) diff --git a/lib/internal/crypto/keys.js b/lib/internal/crypto/keys.js index 41698e5f02939e..c616fbedb06bbd 100644 --- a/lib/internal/crypto/keys.js +++ b/lib/internal/crypto/keys.js @@ -152,7 +152,6 @@ const { const kAsymmetricKeyType = Symbol('kAsymmetricKeyType'); const kAsymmetricKeyDetails = Symbol('kAsymmetricKeyDetails'); - const kAsymmetricKeyJWKProperties = Symbol('kAsymmetricKeyJWKProperties'); function normalizeKeyDetails(details = {}) { if (details.publicExponent !== undefined) { @@ -190,28 +189,6 @@ const { return {}; } } - - [kAsymmetricKeyJWKProperties]() { - switch (this.asymmetricKeyType) { - case 'rsa': return {}; - case 'ec': - switch (this.asymmetricKeyDetails.namedCurve) { - case 'prime256v1': return { crv: 'P-256' }; - case 'secp256k1': return { crv: 'secp256k1' }; - case 'secp384r1': return { crv: 'P-384' }; - case 'secp521r1': return { crv: 'P-521' }; - default: - throw new ERR_CRYPTO_JWK_UNSUPPORTED_CURVE( - this.asymmetricKeyDetails.namedCurve); - } - case 'ed25519': return { crv: 'Ed25519' }; - case 'ed448': return { crv: 'Ed448' }; - case 'x25519': return { crv: 'X25519' }; - case 'x448': return { crv: 'X448' }; - default: - throw new ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE(); - } - } } class PublicKeyObject extends AsymmetricKeyObject { @@ -221,8 +198,7 @@ const { export(options) { if (options && options.format === 'jwk') { - const properties = this[kAsymmetricKeyJWKProperties](); - return this[kHandle].exportJwk(properties); + return this[kHandle].exportJwk({}); } const { format, @@ -243,8 +219,7 @@ const { throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS( 'jwk', 'does not support encryption'); } - const properties = this[kAsymmetricKeyJWKProperties](); - return this[kHandle].exportJwk(properties); + return this[kHandle].exportJwk({}); } const { format, diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 56a0ef8fb06a14..ab9806314e65d3 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -923,7 +923,6 @@ E('ERR_CRYPTO_INVALID_JWK', 'Invalid JWK data', TypeError); E('ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE', 'Invalid key object type %s, expected %s.', TypeError); E('ERR_CRYPTO_INVALID_STATE', 'Invalid state for operation %s', Error); -E('ERR_CRYPTO_JWK_UNSUPPORTED_CURVE', 'Unsupported JWK EC curve: %s.', Error); E('ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE', 'Unsupported JWK Key Type.', Error); E('ERR_CRYPTO_PBKDF2_ERROR', 'PBKDF2 error', Error); E('ERR_CRYPTO_SCRYPT_INVALID_PARAMETER', 'Invalid scrypt parameter', Error); diff --git a/src/crypto/crypto_ec.cc b/src/crypto/crypto_ec.cc index f0ad45529e0039..6497c3f6a56730 100644 --- a/src/crypto/crypto_ec.cc +++ b/src/crypto/crypto_ec.cc @@ -740,6 +740,33 @@ Maybe ExportJWKEcKey( return Nothing(); } + Local crv_name; + const int nid = EC_GROUP_get_curve_name(group); + switch (nid) { + case NID_X9_62_prime256v1: + crv_name = OneByteString(env->isolate(), "P-256"); + break; + case NID_secp256k1: + crv_name = OneByteString(env->isolate(), "secp256k1"); + break; + case NID_secp384r1: + crv_name = OneByteString(env->isolate(), "P-384"); + break; + case NID_secp521r1: + crv_name = OneByteString(env->isolate(), "P-521"); + break; + default: + ERR_CRYPTO_JWK_UNSUPPORTED_CURVE(env->isolate(), + "Unsupported JWK EC curve: %s.", + OBJ_nid2sn(nid)); + } + if (target->Set( + env->context(), + env->jwk_crv_string(), + crv_name).IsNothing()) { + return Nothing(); + } + if (key->GetKeyType() == kKeyTypePrivate) { const BIGNUM* pvt = EC_KEY_get0_private_key(ec); return SetEncodedValue( diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc index 89ad0874e0ffb9..468236aa65e9da 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc @@ -501,6 +501,8 @@ Maybe ExportJWKAsymmetricKey( case EVP_PKEY_X25519: // Fall through case EVP_PKEY_X448: return ExportJWKEdKey(env, key, target); + default: + ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE(env->isolate()); } THROW_ERR_CRYPTO_INVALID_KEYTYPE(env); return Just(false); diff --git a/src/node_errors.h b/src/node_errors.h index 96659f3a400826..0f70fe81b9aa1c 100644 --- a/src/node_errors.h +++ b/src/node_errors.h @@ -49,6 +49,8 @@ void OnFatalError(const char* location, const char* message); V(ERR_CRYPTO_INVALID_SCRYPT_PARAMS, RangeError) \ V(ERR_CRYPTO_INVALID_STATE, Error) \ V(ERR_CRYPTO_INVALID_TAG_LENGTH, RangeError) \ + V(ERR_CRYPTO_JWK_UNSUPPORTED_CURVE, Error) \ + V(ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE, Error) \ V(ERR_CRYPTO_OPERATION_FAILED, Error) \ V(ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH, RangeError) \ V(ERR_CRYPTO_UNKNOWN_CIPHER, Error) \ @@ -136,6 +138,7 @@ ERRORS_WITH_CODE(V) V(ERR_CRYPTO_INVALID_SCRYPT_PARAMS, "Invalid scrypt params") \ V(ERR_CRYPTO_INVALID_STATE, "Invalid state") \ V(ERR_CRYPTO_INVALID_TAG_LENGTH, "Invalid taglength") \ + V(ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE, "Unsupported JWK Key Type.") \ V(ERR_CRYPTO_OPERATION_FAILED, "Operation failed") \ V(ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH, \ "Input buffers must have the same byte length") \ From 353a397f9ee7912ddd6cc382794b60075ae28941 Mon Sep 17 00:00:00 2001 From: himself65 Date: Mon, 19 Jul 2021 15:40:54 +0800 Subject: [PATCH 08/17] fixup!: lint fixes --- lib/internal/crypto/keys.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/internal/crypto/keys.js b/lib/internal/crypto/keys.js index c616fbedb06bbd..27e28942fdaa8a 100644 --- a/lib/internal/crypto/keys.js +++ b/lib/internal/crypto/keys.js @@ -38,8 +38,6 @@ const { ERR_INVALID_ARG_VALUE, ERR_OUT_OF_RANGE, ERR_OPERATION_FAILED, - ERR_CRYPTO_JWK_UNSUPPORTED_CURVE, - ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE, ERR_CRYPTO_INVALID_JWK, } } = require('internal/errors'); From bf63e1a51d75ebb8ea093f1dfbc12e519138b273 Mon Sep 17 00:00:00 2001 From: himself65 Date: Mon, 19 Jul 2021 15:41:11 +0800 Subject: [PATCH 09/17] fixup!: remove unused --- lib/internal/errors.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/internal/errors.js b/lib/internal/errors.js index ab9806314e65d3..aac1b4b1530cf1 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -923,7 +923,6 @@ E('ERR_CRYPTO_INVALID_JWK', 'Invalid JWK data', TypeError); E('ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE', 'Invalid key object type %s, expected %s.', TypeError); E('ERR_CRYPTO_INVALID_STATE', 'Invalid state for operation %s', Error); -E('ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE', 'Unsupported JWK Key Type.', Error); E('ERR_CRYPTO_PBKDF2_ERROR', 'PBKDF2 error', Error); E('ERR_CRYPTO_SCRYPT_INVALID_PARAMETER', 'Invalid scrypt parameter', Error); E('ERR_CRYPTO_SCRYPT_NOT_SUPPORTED', 'Scrypt algorithm not supported', Error); From b9eb514b1b6f0aadcb24bb76be256d377be40108 Mon Sep 17 00:00:00 2001 From: himself65 Date: Mon, 19 Jul 2021 15:43:52 +0800 Subject: [PATCH 10/17] fixup!: cpp lint fix --- src/crypto/crypto_keys.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc index 468236aa65e9da..03f1c19e8e3a2c 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc @@ -63,8 +63,7 @@ void GetKeyFormatAndTypeFromJs( } else { CHECK( (context == kKeyContextInput && config->format_ == kKeyFormatPEM) || - (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK) - ); + (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK)); CHECK(args[*offset + 1]->IsNullOrUndefined()); config->type_ = Nothing(); } From 7789ff46c6c6b379b19bc122ec0a1692dc9f2b9f Mon Sep 17 00:00:00 2001 From: himself65 Date: Mon, 19 Jul 2021 15:51:29 +0800 Subject: [PATCH 11/17] fixup!: cpp lint fix --- src/crypto/crypto_keys.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc index 03f1c19e8e3a2c..97cae80ee2e246 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc @@ -62,8 +62,10 @@ void GetKeyFormatAndTypeFromJs( args[*offset + 1].As()->Value())); } else { CHECK( - (context == kKeyContextInput && config->format_ == kKeyFormatPEM) || - (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK)); + (context == kKeyContextInput && + config->format_ == kKeyFormatPEM) || + (context == kKeyContextGenerate && + config->format_ == kKeyFormatJWK)); CHECK(args[*offset + 1]->IsNullOrUndefined()); config->type_ = Nothing(); } From 1a31ba43f453e59350ab5337bd09e77cf6ac6c5c Mon Sep 17 00:00:00 2001 From: himself65 Date: Mon, 19 Jul 2021 16:18:49 +0800 Subject: [PATCH 12/17] fixup!: error --- src/crypto/crypto_keys.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc index 97cae80ee2e246..18f67c02dcdd99 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc @@ -502,10 +502,8 @@ Maybe ExportJWKAsymmetricKey( case EVP_PKEY_X25519: // Fall through case EVP_PKEY_X448: return ExportJWKEdKey(env, key, target); - default: - ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE(env->isolate()); } - THROW_ERR_CRYPTO_INVALID_KEYTYPE(env); + THROW_ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE(env); return Just(false); } From 91a4cb94df9d1c0db10d88775b603e3ad06b2840 Mon Sep 17 00:00:00 2001 From: himself65 Date: Mon, 19 Jul 2021 17:29:27 +0800 Subject: [PATCH 13/17] fixup!: code typo --- src/crypto/crypto_ec.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/crypto/crypto_ec.cc b/src/crypto/crypto_ec.cc index 6497c3f6a56730..2abe570080e21d 100644 --- a/src/crypto/crypto_ec.cc +++ b/src/crypto/crypto_ec.cc @@ -755,10 +755,11 @@ Maybe ExportJWKEcKey( case NID_secp521r1: crv_name = OneByteString(env->isolate(), "P-521"); break; - default: - ERR_CRYPTO_JWK_UNSUPPORTED_CURVE(env->isolate(), - "Unsupported JWK EC curve: %s.", - OBJ_nid2sn(nid)); + default: { + THROW_ERR_CRYPTO_JWK_UNSUPPORTED_CURVE( + env, "Unsupported JWK EC curve: %s.", OBJ_nid2sn(nid)); + return Nothing(); + } } if (target->Set( env->context(), From f6ff5af2f82ac411e137a3d72bc08cde31d2b836 Mon Sep 17 00:00:00 2001 From: himself65 Date: Mon, 19 Jul 2021 17:46:36 +0800 Subject: [PATCH 14/17] fixup!: add one case when unsupported ec curve --- test/parallel/test-crypto-keygen.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index 490886203823a1..de5d2a5d8dedc7 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -648,6 +648,19 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); message: "The property 'options.paramEncoding' is invalid. " + "Received 'otherEncoding'" }); + assert.throws(() => generateKeyPairSync('ec', { + namedCurve: 'secp224r1', + publicKeyEncoding: { + format: 'jwk' + }, + privateKeyEncoding: { + format: 'jwk' + } + }), { + name: 'Error', + code: 'ERR_CRYPTO_JWK_UNSUPPORTED_CURVE', + message: 'Unsupported JWK EC curve: secp224r1.' + }); } { From a61d4636ab60531adfbb217d4511207944931e05 Mon Sep 17 00:00:00 2001 From: himself65 Date: Mon, 19 Jul 2021 18:18:16 +0800 Subject: [PATCH 15/17] fixup!: test cases for all type and curves --- test/parallel/test-crypto-keygen.js | 120 +++++++++++++++++++++++----- 1 file changed, 101 insertions(+), 19 deletions(-) diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index de5d2a5d8dedc7..5f070c54809327 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -605,26 +605,95 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); })); // Test async elliptic curve key generation with 'jwk' encoding - generateKeyPair('ec', { - namedCurve: 'P-384', - publicKeyEncoding: { - format: 'jwk' - }, - privateKeyEncoding: { - format: 'jwk' + [ + ['ec', ['P-384', 'P-256', 'P-521', 'secp256k1']], + ['rsa'], + ['rsa-pss'], + ['ed25519'], + ['ed448'], + ['x25519'], + ['x448'], + ].forEach((types) => { + const [type, options] = types; + switch (type) { + case 'ec': { + return options.forEach((curve) => { + generateKeyPair(type, { + namedCurve: curve, + publicKeyEncoding: { + format: 'jwk' + }, + privateKeyEncoding: { + 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(!publicKey.d); + assert(privateKey.d); + assert.strictEqual(publicKey.kty, 'EC'); + assert.strictEqual(publicKey.kty, privateKey.kty); + assert.strictEqual(publicKey.crv, curve); + assert.strictEqual(publicKey.crv, privateKey.crv); + })); + }); + } + case 'rsa': + // Fall through + case 'rsa-pss': { + return generateKeyPair(type, { + modulusLength: 4096, + publicKeyEncoding: { + format: 'jwk' + }, + privateKeyEncoding: { + format: 'jwk' + } + }, common.mustSucceed((publicKey, privateKey) => { + assert.strictEqual(typeof publicKey, 'object'); + assert.strictEqual(typeof privateKey, 'object'); + assert.strictEqual(publicKey.kty, 'RSA'); + assert.strictEqual(publicKey.kty, privateKey.kty); + assert.strictEqual(typeof publicKey.n, 'string'); + assert.strictEqual(publicKey.n, privateKey.n); + assert.strictEqual(typeof publicKey.e, 'string'); + assert.strictEqual(publicKey.e, privateKey.e); + assert.strictEqual(typeof privateKey.d, 'string'); + assert.strictEqual(typeof privateKey.p, 'string'); + assert.strictEqual(typeof privateKey.q, 'string'); + assert.strictEqual(typeof privateKey.dp, 'string'); + assert.strictEqual(typeof privateKey.dq, 'string'); + assert.strictEqual(typeof privateKey.qi, 'string'); + })); + } + case 'ed25519': + case 'ed448': + case 'x25519': + case 'x448': { + generateKeyPair(type, { + publicKeyEncoding: { + format: 'jwk' + }, + privateKeyEncoding: { + format: 'jwk' + } + }, common.mustSucceed((publicKey, privateKey) => { + assert.strictEqual(typeof publicKey, 'object'); + assert.strictEqual(typeof privateKey, 'object'); + assert.strictEqual(publicKey.x, privateKey.x); + assert(!publicKey.d); + assert(privateKey.d); + assert.strictEqual(publicKey.kty, 'OKP'); + assert.strictEqual(publicKey.kty, privateKey.kty); + const expectedCrv = `${type.charAt(0).toUpperCase()}${type.slice(1)}`; + assert.strictEqual(publicKey.crv, expectedCrv); + assert.strictEqual(publicKey.crv, privateKey.crv); + })); + } } - }, 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(!publicKey.d); - assert(privateKey.d); - assert.strictEqual(publicKey.kty, 'EC'); - assert.strictEqual(publicKey.kty, privateKey.kty); - assert.strictEqual(publicKey.crv, 'P-384'); - assert.strictEqual(publicKey.crv, privateKey.crv); - })); + }); } // Test invalid parameter encoding. @@ -648,6 +717,19 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); message: "The property 'options.paramEncoding' is invalid. " + "Received 'otherEncoding'" }); + assert.throws(() => generateKeyPairSync('dsa', { + modulusLength: 4096, + publicKeyEncoding: { + format: 'jwk' + }, + privateKeyEncoding: { + format: 'jwk' + } + }), { + name: 'Error', + code: 'ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE', + message: 'Unsupported JWK Key Type.' + }); assert.throws(() => generateKeyPairSync('ec', { namedCurve: 'secp224r1', publicKeyEncoding: { From 112f25d4d072b88a08916e8e8570033c6e2dd86a Mon Sep 17 00:00:00 2001 From: himself65 Date: Mon, 19 Jul 2021 18:29:28 +0800 Subject: [PATCH 16/17] fixup!: remove unused comment --- test/parallel/test-crypto-keygen.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index 5f070c54809327..61e1462f12fce8 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -641,7 +641,6 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); }); } case 'rsa': - // Fall through case 'rsa-pss': { return generateKeyPair(type, { modulusLength: 4096, From 700fc5fc986a1e4372d095634ca0a84f73c267fd Mon Sep 17 00:00:00 2001 From: himself65 Date: Mon, 19 Jul 2021 20:24:30 +0800 Subject: [PATCH 17/17] fixup!: not support export rsa-pss --- src/crypto/crypto_keys.cc | 4 +--- test/parallel/test-crypto-keygen.js | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc index 18f67c02dcdd99..821a06b1bd1417 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc @@ -491,9 +491,7 @@ Maybe ExportJWKAsymmetricKey( std::shared_ptr key, Local target) { switch (EVP_PKEY_id(key->GetAsymmetricKey().get())) { - case EVP_PKEY_RSA: - // Fall through - case EVP_PKEY_RSA_PSS: return ExportJWKRsaKey(env, key, target); + case EVP_PKEY_RSA: return ExportJWKRsaKey(env, key, target); case EVP_PKEY_EC: return ExportJWKEcKey(env, key, target); case EVP_PKEY_ED25519: // Fall through diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index 61e1462f12fce8..5572b6a2e155e4 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -608,7 +608,6 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); [ ['ec', ['P-384', 'P-256', 'P-521', 'secp256k1']], ['rsa'], - ['rsa-pss'], ['ed25519'], ['ed448'], ['x25519'], @@ -640,8 +639,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); })); }); } - case 'rsa': - case 'rsa-pss': { + case 'rsa': { return generateKeyPair(type, { modulusLength: 4096, publicKeyEncoding: {