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 eaaaa0d

Browse filesBrowse files
tniessenaddaleax
authored andcommitted
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: #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>
1 parent 1e20c5e commit eaaaa0d
Copy full SHA for eaaaa0d

File tree

Expand file treeCollapse file tree

5 files changed

+34
-42
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

5 files changed

+34
-42
lines changed
Open diff view settings
Collapse file

‎doc/api/crypto.md‎

Copy file name to clipboardExpand all lines: doc/api/crypto.md
+16Lines changed: 16 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -1379,6 +1379,9 @@ This can be called many times with new data as it is streamed.
13791379
<!-- YAML
13801380
added: v0.1.92
13811381
changes:
1382+
- version: REPLACEME
1383+
pr-url: https://github.com/nodejs/node/pull/25217
1384+
description: The key can now be a private key.
13821385
- version: v8.0.0
13831386
pr-url: https://github.com/nodejs/node/pull/11705
13841387
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
14191422
called. Multiple calls to `verify.verify()` will result in an error being
14201423
thrown.
14211424

1425+
Because public keys can be derived from private keys, a private key may
1426+
be passed instead of a public key.
1427+
14221428
## `crypto` module methods and properties
14231429

14241430
### crypto.constants
@@ -1829,6 +1835,10 @@ must be an object with the properties described above.
18291835
### crypto.createPublicKey(key)
18301836
<!-- YAML
18311837
added: v11.6.0
1838+
changes:
1839+
- version: REPLACEME
1840+
pr-url: https://github.com/nodejs/node/pull/25217
1841+
description: The `key` argument can now be a private key.
18321842
-->
18331843
* `key` {Object | string | Buffer}
18341844
- `key`: {string | Buffer}
@@ -1843,6 +1853,12 @@ must be an object with the properties described above.
18431853

18441854
If the format is `'pem'`, the `'key'` may also be an X.509 certificate.
18451855

1856+
Because public keys can be derived from private keys, a private key may be
1857+
passed instead of a public key. In that case, this function behaves as if
1858+
[`crypto.createPrivateKey()`][] had been called, except that the type of the
1859+
returned `KeyObject` will be `public` and that the private key cannot be
1860+
extracted from the returned `KeyObject`.
1861+
18461862
### crypto.createSecretKey(key)
18471863
<!-- YAML
18481864
added: v11.6.0
Collapse file

‎lib/internal/crypto/keys.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/keys.js
+1-6Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,6 @@ function prepareAsymmetricKey(key, isPublic, allowKeyObject = true) {
261261
}
262262
}
263263

264-
function preparePublicKey(key, allowKeyObject) {
265-
return prepareAsymmetricKey(key, true, allowKeyObject);
266-
}
267-
268264
function preparePrivateKey(key, allowKeyObject) {
269265
return prepareAsymmetricKey(key, false, allowKeyObject);
270266
}
@@ -300,7 +296,7 @@ function createSecretKey(key) {
300296
}
301297

302298
function createPublicKey(key) {
303-
const { format, type, data } = preparePublicKey(key, false);
299+
const { format, type, data } = preparePublicOrPrivateKey(key, false);
304300
const handle = new KeyObjectHandle(kKeyTypePublic);
305301
handle.init(data, format, type);
306302
return new PublicKeyObject(handle);
@@ -326,7 +322,6 @@ module.exports = {
326322
// These are designed for internal use only and should not be exposed.
327323
parsePublicKeyEncoding,
328324
parsePrivateKeyEncoding,
329-
preparePublicKey,
330325
preparePrivateKey,
331326
preparePublicOrPrivateKey,
332327
prepareSecretKey,
Collapse file

‎lib/internal/crypto/sig.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/sig.js
+5-4Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const {
1919
} = require('internal/crypto/util');
2020
const {
2121
preparePrivateKey,
22-
preparePublicKey
22+
preparePublicOrPrivateKey
2323
} = require('internal/crypto/keys');
2424
const { Writable } = require('stream');
2525
const { inherits } = require('util');
@@ -111,8 +111,9 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) {
111111
const {
112112
data,
113113
format,
114-
type
115-
} = preparePublicKey(options, true);
114+
type,
115+
passphrase
116+
} = preparePublicOrPrivateKey(options, true);
116117

117118
sigEncoding = sigEncoding || getDefaultEncoding();
118119

@@ -124,7 +125,7 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) {
124125
signature = validateArrayBufferView(toBuf(signature, sigEncoding),
125126
'signature');
126127

127-
return this[kHandle].verify(data, format, type, signature,
128+
return this[kHandle].verify(data, format, type, passphrase, signature,
128129
rsaPadding, pssSaltLength);
129130
};
130131

Collapse file

‎src/node_crypto.cc‎

Copy file name to clipboardExpand all lines: src/node_crypto.cc
+2-26Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2995,30 +2995,6 @@ static PublicKeyEncodingConfig GetPublicKeyEncodingFromJs(
29952995
return result;
29962996
}
29972997

2998-
static ManagedEVPPKey GetPublicKeyFromJs(
2999-
const FunctionCallbackInfo<Value>& args,
3000-
unsigned int* offset,
3001-
bool allow_key_object) {
3002-
if (args[*offset]->IsString() || Buffer::HasInstance(args[*offset])) {
3003-
Environment* env = Environment::GetCurrent(args);
3004-
ByteSource key = ByteSource::FromStringOrBuffer(env, args[(*offset)++]);
3005-
PublicKeyEncodingConfig config =
3006-
GetPublicKeyEncodingFromJs(args, offset, kKeyContextInput);
3007-
EVPKeyPointer pkey;
3008-
ParsePublicKey(&pkey, config, key.get(), key.size());
3009-
if (!pkey)
3010-
ThrowCryptoError(env, ERR_get_error(), "Failed to read public key");
3011-
return ManagedEVPPKey(pkey.release());
3012-
} else {
3013-
CHECK(args[*offset]->IsObject() && allow_key_object);
3014-
KeyObject* key;
3015-
ASSIGN_OR_RETURN_UNWRAP(&key, args[*offset].As<Object>(), ManagedEVPPKey());
3016-
CHECK_EQ(key->GetKeyType(), kKeyTypePublic);
3017-
(*offset) += 3;
3018-
return key->GetAsymmetricKey();
3019-
}
3020-
}
3021-
30222998
static NonCopyableMaybe<PrivateKeyEncodingConfig> GetPrivateKeyEncodingFromJs(
30232999
const FunctionCallbackInfo<Value>& args,
30243000
unsigned int* offset,
@@ -3380,7 +3356,7 @@ void KeyObject::Init(const FunctionCallbackInfo<Value>& args) {
33803356
CHECK_EQ(args.Length(), 3);
33813357

33823358
offset = 0;
3383-
pkey = GetPublicKeyFromJs(args, &offset, false);
3359+
pkey = GetPublicOrPrivateKeyFromJs(args, &offset, false);
33843360
if (!pkey)
33853361
return;
33863362
key->InitPublic(pkey);
@@ -4662,7 +4638,7 @@ void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& args) {
46624638
ASSIGN_OR_RETURN_UNWRAP(&verify, args.Holder());
46634639

46644640
unsigned int offset = 0;
4665-
ManagedEVPPKey pkey = GetPublicKeyFromJs(args, &offset, true);
4641+
ManagedEVPPKey pkey = GetPublicOrPrivateKeyFromJs(args, &offset, true);
46664642

46674643
char* hbuf = Buffer::Data(args[offset]);
46684644
ssize_t hlen = Buffer::Length(args[offset]);
Collapse file

‎test/parallel/test-crypto-keygen.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-crypto-keygen.js
+10-6Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,23 @@ function assertApproximateSize(key, expectedSize) {
3131
function testEncryptDecrypt(publicKey, privateKey) {
3232
const message = 'Hello Node.js world!';
3333
const plaintext = Buffer.from(message, 'utf8');
34-
const ciphertext = publicEncrypt(publicKey, plaintext);
35-
const received = privateDecrypt(privateKey, ciphertext);
36-
assert.strictEqual(received.toString('utf8'), message);
34+
for (const key of [publicKey, privateKey]) {
35+
const ciphertext = publicEncrypt(key, plaintext);
36+
const received = privateDecrypt(privateKey, ciphertext);
37+
assert.strictEqual(received.toString('utf8'), message);
38+
}
3739
}
3840

3941
// Tests that a key pair can be used for signing / verification.
4042
function testSignVerify(publicKey, privateKey) {
4143
const message = 'Hello Node.js world!';
4244
const signature = createSign('SHA256').update(message)
4345
.sign(privateKey, 'hex');
44-
const okay = createVerify('SHA256').update(message)
45-
.verify(publicKey, signature, 'hex');
46-
assert(okay);
46+
for (const key of [publicKey, privateKey]) {
47+
const okay = createVerify('SHA256').update(message)
48+
.verify(key, signature, 'hex');
49+
assert(okay);
50+
}
4751
}
4852

4953
// Constructs a regular expression for a PEM-encoded key with the given label.

0 commit comments

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