summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Nießen <tniessen@tnie.de>2018-12-25 13:13:52 +0100
committerAnna Henningsen <anna@addaleax.net>2019-01-08 00:20:09 +0100
commitae2d1f0e05449221ee770a393e5c967b359d9b1b (patch)
tree5d43c4d7b0509e47ca51ad7e6cfb4d3192c29f61
parent27a03b84c42a021c94649b3f601800b7502a9c15 (diff)
downloadandroid-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.md16
-rw-r--r--lib/internal/crypto/keys.js7
-rw-r--r--lib/internal/crypto/sig.js9
-rw-r--r--src/node_crypto.cc28
-rw-r--r--test/parallel/test-crypto-keygen.js16
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.