diff options
author | Tobias Nießen <tniessen@tnie.de> | 2018-12-25 13:13:52 +0100 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2019-01-08 00:20:09 +0100 |
commit | ae2d1f0e05449221ee770a393e5c967b359d9b1b (patch) | |
tree | 5d43c4d7b0509e47ca51ad7e6cfb4d3192c29f61 | |
parent | 27a03b84c42a021c94649b3f601800b7502a9c15 (diff) | |
download | android-node-v8-ae2d1f0e05449221ee770a393e5c967b359d9b1b.tar.gz android-node-v8-ae2d1f0e05449221ee770a393e5c967b359d9b1b.tar.bz2 android-node-v8-ae2d1f0e05449221ee770a393e5c967b359d9b1b.zip |
crypto: always accept private keys as public keys
Some APIs already accept private keys instead of public keys. This
changes all relevant crypto APIs to do so.
PR-URL: https://github.com/nodejs/node/pull/25217
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
-rw-r--r-- | doc/api/crypto.md | 16 | ||||
-rw-r--r-- | lib/internal/crypto/keys.js | 7 | ||||
-rw-r--r-- | lib/internal/crypto/sig.js | 9 | ||||
-rw-r--r-- | src/node_crypto.cc | 28 | ||||
-rw-r--r-- | test/parallel/test-crypto-keygen.js | 16 |
5 files changed, 34 insertions, 42 deletions
diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 95b1e9114a..2605393878 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -1379,6 +1379,9 @@ This can be called many times with new data as it is streamed. <!-- YAML added: v0.1.92 changes: + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/25217 + description: The key can now be a private key. - version: v8.0.0 pr-url: https://github.com/nodejs/node/pull/11705 description: Support for RSASSA-PSS and additional options was added. @@ -1419,6 +1422,9 @@ The `verify` object can not be used again after `verify.verify()` has been called. Multiple calls to `verify.verify()` will result in an error being thrown. +Because public keys can be derived from private keys, a private key may +be passed instead of a public key. + ## `crypto` module methods and properties ### crypto.constants @@ -1829,6 +1835,10 @@ must be an object with the properties described above. ### crypto.createPublicKey(key) <!-- YAML added: v11.6.0 +changes: + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/25217 + description: The `key` argument can now be a private key. --> * `key` {Object | string | Buffer} - `key`: {string | Buffer} @@ -1843,6 +1853,12 @@ must be an object with the properties described above. If the format is `'pem'`, the `'key'` may also be an X.509 certificate. +Because public keys can be derived from private keys, a private key may be +passed instead of a public key. In that case, this function behaves as if +[`crypto.createPrivateKey()`][] had been called, except that the type of the +returned `KeyObject` will be `public` and that the private key cannot be +extracted from the returned `KeyObject`. + ### crypto.createSecretKey(key) <!-- YAML added: v11.6.0 diff --git a/lib/internal/crypto/keys.js b/lib/internal/crypto/keys.js index ad82835080..db7be824ac 100644 --- a/lib/internal/crypto/keys.js +++ b/lib/internal/crypto/keys.js @@ -261,10 +261,6 @@ function prepareAsymmetricKey(key, isPublic, allowKeyObject = true) { } } -function preparePublicKey(key, allowKeyObject) { - return prepareAsymmetricKey(key, true, allowKeyObject); -} - function preparePrivateKey(key, allowKeyObject) { return prepareAsymmetricKey(key, false, allowKeyObject); } @@ -300,7 +296,7 @@ function createSecretKey(key) { } function createPublicKey(key) { - const { format, type, data } = preparePublicKey(key, false); + const { format, type, data } = preparePublicOrPrivateKey(key, false); const handle = new KeyObjectHandle(kKeyTypePublic); handle.init(data, format, type); return new PublicKeyObject(handle); @@ -326,7 +322,6 @@ module.exports = { // These are designed for internal use only and should not be exposed. parsePublicKeyEncoding, parsePrivateKeyEncoding, - preparePublicKey, preparePrivateKey, preparePublicOrPrivateKey, prepareSecretKey, diff --git a/lib/internal/crypto/sig.js b/lib/internal/crypto/sig.js index 32f7c37ec2..4a0c66f9cf 100644 --- a/lib/internal/crypto/sig.js +++ b/lib/internal/crypto/sig.js @@ -19,7 +19,7 @@ const { } = require('internal/crypto/util'); const { preparePrivateKey, - preparePublicKey + preparePublicOrPrivateKey } = require('internal/crypto/keys'); const { Writable } = require('stream'); @@ -112,8 +112,9 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) { const { data, format, - type - } = preparePublicKey(options, true); + type, + passphrase + } = preparePublicOrPrivateKey(options, true); sigEncoding = sigEncoding || getDefaultEncoding(); @@ -125,7 +126,7 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) { signature = validateArrayBufferView(toBuf(signature, sigEncoding), 'signature'); - return this[kHandle].verify(data, format, type, signature, + return this[kHandle].verify(data, format, type, passphrase, signature, rsaPadding, pssSaltLength); }; diff --git a/src/node_crypto.cc b/src/node_crypto.cc index ab35568888..ff3713eeec 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -3012,30 +3012,6 @@ static PublicKeyEncodingConfig GetPublicKeyEncodingFromJs( return result; } -static ManagedEVPPKey GetPublicKeyFromJs( - const FunctionCallbackInfo<Value>& args, - unsigned int* offset, - bool allow_key_object) { - if (args[*offset]->IsString() || Buffer::HasInstance(args[*offset])) { - Environment* env = Environment::GetCurrent(args); - ByteSource key = ByteSource::FromStringOrBuffer(env, args[(*offset)++]); - PublicKeyEncodingConfig config = - GetPublicKeyEncodingFromJs(args, offset, kKeyContextInput); - EVPKeyPointer pkey; - ParsePublicKey(&pkey, config, key.get(), key.size()); - if (!pkey) - ThrowCryptoError(env, ERR_get_error(), "Failed to read public key"); - return ManagedEVPPKey(pkey.release()); - } else { - CHECK(args[*offset]->IsObject() && allow_key_object); - KeyObject* key; - ASSIGN_OR_RETURN_UNWRAP(&key, args[*offset].As<Object>(), ManagedEVPPKey()); - CHECK_EQ(key->GetKeyType(), kKeyTypePublic); - (*offset) += 3; - return key->GetAsymmetricKey(); - } -} - static NonCopyableMaybe<PrivateKeyEncodingConfig> GetPrivateKeyEncodingFromJs( const FunctionCallbackInfo<Value>& args, unsigned int* offset, @@ -3397,7 +3373,7 @@ void KeyObject::Init(const FunctionCallbackInfo<Value>& args) { CHECK_EQ(args.Length(), 3); offset = 0; - pkey = GetPublicKeyFromJs(args, &offset, false); + pkey = GetPublicOrPrivateKeyFromJs(args, &offset, false); if (!pkey) return; key->InitPublic(pkey); @@ -4679,7 +4655,7 @@ void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& args) { ASSIGN_OR_RETURN_UNWRAP(&verify, args.Holder()); unsigned int offset = 0; - ManagedEVPPKey pkey = GetPublicKeyFromJs(args, &offset, true); + ManagedEVPPKey pkey = GetPublicOrPrivateKeyFromJs(args, &offset, true); char* hbuf = Buffer::Data(args[offset]); ssize_t hlen = Buffer::Length(args[offset]); diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index aabd92e369..61cd69b5d6 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -31,9 +31,11 @@ function assertApproximateSize(key, expectedSize) { function testEncryptDecrypt(publicKey, privateKey) { const message = 'Hello Node.js world!'; const plaintext = Buffer.from(message, 'utf8'); - const ciphertext = publicEncrypt(publicKey, plaintext); - const received = privateDecrypt(privateKey, ciphertext); - assert.strictEqual(received.toString('utf8'), message); + for (const key of [publicKey, privateKey]) { + const ciphertext = publicEncrypt(key, plaintext); + const received = privateDecrypt(privateKey, ciphertext); + assert.strictEqual(received.toString('utf8'), message); + } } // Tests that a key pair can be used for signing / verification. @@ -41,9 +43,11 @@ function testSignVerify(publicKey, privateKey) { const message = 'Hello Node.js world!'; const signature = createSign('SHA256').update(message) .sign(privateKey, 'hex'); - const okay = createVerify('SHA256').update(message) - .verify(publicKey, signature, 'hex'); - assert(okay); + for (const key of [publicKey, privateKey]) { + const okay = createVerify('SHA256').update(message) + .verify(key, signature, 'hex'); + assert(okay); + } } // Constructs a regular expression for a PEM-encoded key with the given label. |