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 073e84d

Browse filesBrowse files
panvaaduh95
authored andcommitted
crypto: accept key data in crypto.diffieHellman() and cleanup DH jobs
Signed-off-by: Filip Skokan <panva.ip@gmail.com> PR-URL: #62527 Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 28679d7 commit 073e84d
Copy full SHA for 073e84d

9 files changed

+364-198Lines changed: 364 additions & 198 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

‎doc/api/crypto.md‎

Copy file name to clipboardExpand all lines: doc/api/crypto.md
+12-3Lines changed: 12 additions & 3 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -4142,23 +4142,32 @@ added:
41424142
- v13.9.0
41434143
- v12.17.0
41444144
changes:
4145+
- version: REPLACEME
4146+
pr-url: https://github.com/nodejs/node/pull/62527
4147+
description: Accept key data in addition to KeyObject instances.
41454148
- version: v23.11.0
41464149
pr-url: https://github.com/nodejs/node/pull/57274
41474150
description: Optional callback argument added.
41484151
-->
41494152

41504153
* `options` {Object}
4151-
* `privateKey` {KeyObject}
4152-
* `publicKey` {KeyObject}
4154+
* `privateKey` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject}
4155+
* `publicKey` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject}
41534156
* `callback` {Function}
41544157
* `err` {Error}
41554158
* `secret` {Buffer}
41564159
* Returns: {Buffer} if the `callback` function is not provided.
41574160

41584161
Computes the Diffie-Hellman shared secret based on a `privateKey` and a `publicKey`.
4159-
Both keys must have the same `asymmetricKeyType` and must support either the DH or
4162+
Both keys must represent the same asymmetric key type and must support either the DH or
41604163
ECDH operation.
41614164

4165+
If `options.privateKey` is not a [`KeyObject`][], this function behaves as if
4166+
`options.privateKey` had been passed to [`crypto.createPrivateKey()`][].
4167+
4168+
If `options.publicKey` is not a [`KeyObject`][], this function behaves as if
4169+
`options.publicKey` had been passed to [`crypto.createPublicKey()`][].
4170+
41624171
If the `callback` function is provided this function uses libuv's threadpool.
41634172

41644173
### `crypto.encapsulate(key[, callback])`
Collapse file

‎lib/internal/crypto/diffiehellman.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/diffiehellman.js
+61-18Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ const {
1717
DiffieHellman: _DiffieHellman,
1818
DiffieHellmanGroup: _DiffieHellmanGroup,
1919
ECDH: _ECDH,
20-
ECDHBitsJob,
2120
ECDHConvertKey: _ECDHConvertKey,
2221
kCryptoJobAsync,
2322
kCryptoJobSync,
@@ -52,9 +51,11 @@ const {
5251
} = require('internal/util');
5352

5453
const {
55-
KeyObject,
54+
isKeyObject,
5655
kAlgorithm,
5756
kKeyType,
57+
preparePrivateKey,
58+
preparePublicOrPrivateKey,
5859
} = require('internal/crypto/keys');
5960

6061
const {
@@ -284,31 +285,65 @@ function diffieHellman(options, callback) {
284285
validateFunction(callback, 'callback');
285286

286287
const { privateKey, publicKey } = options;
287-
if (!(privateKey instanceof KeyObject))
288+
289+
// TODO(@panva): remove these non-semver-major error code preserving measures
290+
// in a semver-major followup, the final state is just preparePublicOrPrivateKey
291+
// and preparePrivateKey
292+
if (privateKey == null)
288293
throw new ERR_INVALID_ARG_VALUE('options.privateKey', privateKey);
289294

290-
if (!(publicKey instanceof KeyObject))
295+
if (publicKey == null)
291296
throw new ERR_INVALID_ARG_VALUE('options.publicKey', publicKey);
292297

293-
if (privateKey.type !== 'private')
294-
throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(privateKey.type, 'private');
298+
if (isKeyObject(privateKey)) {
299+
if (privateKey.type !== 'private')
300+
throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(privateKey.type, 'private');
301+
}
295302

296-
if (publicKey.type !== 'public' && publicKey.type !== 'private') {
297-
throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(publicKey.type,
298-
'private or public');
303+
if (isKeyObject(publicKey)) {
304+
if (publicKey.type !== 'public' && publicKey.type !== 'private') {
305+
throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(publicKey.type,
306+
'private or public');
307+
}
299308
}
300309

301-
const privateType = privateKey.asymmetricKeyType;
302-
const publicType = publicKey.asymmetricKeyType;
303-
if (privateType !== publicType || !dhEnabledKeyTypes.has(privateType)) {
304-
throw new ERR_CRYPTO_INCOMPATIBLE_KEY('key types for Diffie-Hellman',
305-
`${privateType} and ${publicType}`);
310+
if (isKeyObject(privateKey) && isKeyObject(publicKey)) {
311+
const privateType = privateKey.asymmetricKeyType;
312+
const publicType = publicKey.asymmetricKeyType;
313+
if (privateType !== publicType || !dhEnabledKeyTypes.has(privateType)) {
314+
throw new ERR_CRYPTO_INCOMPATIBLE_KEY('key types for Diffie-Hellman',
315+
`${privateType} and ${publicType}`);
316+
}
306317
}
307318

319+
const {
320+
data: pubData,
321+
format: pubFormat,
322+
type: pubType,
323+
passphrase: pubPassphrase,
324+
namedCurve: pubNamedCurve,
325+
} = preparePublicOrPrivateKey(publicKey, 'options.publicKey');
326+
327+
const {
328+
data: privData,
329+
format: privFormat,
330+
type: privType,
331+
passphrase: privPassphrase,
332+
namedCurve: privNamedCurve,
333+
} = preparePrivateKey(privateKey, 'options.privateKey');
334+
308335
const job = new DHBitsJob(
309336
callback ? kCryptoJobAsync : kCryptoJobSync,
310-
publicKey[kHandle],
311-
privateKey[kHandle]);
337+
pubData,
338+
pubFormat,
339+
pubType,
340+
pubPassphrase,
341+
pubNamedCurve,
342+
privData,
343+
privFormat,
344+
privType,
345+
privPassphrase,
346+
privNamedCurve);
312347

313348
if (!callback) {
314349
const { 0: err, 1: secret } = job.run();
@@ -349,10 +384,18 @@ async function ecdhDeriveBits(algorithm, baseKey, length) {
349384
throw lazyDOMException('Named curve mismatch', 'InvalidAccessError');
350385
}
351386

352-
const bits = await jobPromise(() => new ECDHBitsJob(
387+
const bits = await jobPromise(() => new DHBitsJob(
353388
kCryptoJobAsync,
354389
key[kKeyObject][kHandle],
355-
baseKey[kKeyObject][kHandle]));
390+
undefined,
391+
undefined,
392+
undefined,
393+
undefined,
394+
baseKey[kKeyObject][kHandle],
395+
undefined,
396+
undefined,
397+
undefined,
398+
undefined));
356399

357400
// If a length is not specified, return the full derived secret
358401
if (length === null)
Collapse file

‎lib/internal/crypto/keys.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/keys.js
+14-14Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ function getKeyTypes(allowKeyObject, bufferOnly = false) {
628628
}
629629

630630

631-
function prepareAsymmetricKey(key, ctx) {
631+
function prepareAsymmetricKey(key, ctx, name = 'key') {
632632
if (isKeyObject(key)) {
633633
// Best case: A key object, as simple as that.
634634
return { data: getKeyObjectHandle(key, ctx) };
@@ -639,7 +639,7 @@ function prepareAsymmetricKey(key, ctx) {
639639
}
640640
if (isStringOrBuffer(key)) {
641641
// Expect PEM by default, mostly for backward compatibility.
642-
return { format: kKeyFormatPEM, data: getArrayBufferOrView(key, 'key') };
642+
return { format: kKeyFormatPEM, data: getArrayBufferOrView(key, name) };
643643
}
644644
if (typeof key === 'object') {
645645
const { key: data, encoding, format } = key;
@@ -654,23 +654,23 @@ function prepareAsymmetricKey(key, ctx) {
654654
return { data: getKeyObjectHandle(data[kKeyObject], ctx) };
655655
}
656656
if (format === 'jwk') {
657-
validateObject(data, 'key.key');
657+
validateObject(data, `${name}.key`);
658658
return { data, format: kKeyFormatJWK };
659659
} else if (format === 'raw-public' || format === 'raw-private' ||
660660
format === 'raw-seed') {
661661
if (!isStringOrBuffer(data)) {
662662
throw new ERR_INVALID_ARG_TYPE(
663-
'key.key',
663+
`${name}.key`,
664664
['ArrayBuffer', 'Buffer', 'TypedArray', 'DataView'],
665665
data);
666666
}
667-
validateString(key.asymmetricKeyType, 'key.asymmetricKeyType');
667+
validateString(key.asymmetricKeyType, `${name}.asymmetricKeyType`);
668668
if (key.asymmetricKeyType === 'ec') {
669-
validateString(key.namedCurve, 'key.namedCurve');
669+
validateString(key.namedCurve, `${name}.namedCurve`);
670670
}
671671
const rawFormat = parseKeyFormat(format, undefined, 'options.format');
672672
return {
673-
data: getArrayBufferOrView(data, 'key.key'),
673+
data: getArrayBufferOrView(data, `${name}.key`),
674674
format: rawFormat,
675675
type: key.asymmetricKeyType,
676676
namedCurve: key.namedCurve ?? null,
@@ -680,31 +680,31 @@ function prepareAsymmetricKey(key, ctx) {
680680
// Either PEM or DER using PKCS#1 or SPKI.
681681
if (!isStringOrBuffer(data)) {
682682
throw new ERR_INVALID_ARG_TYPE(
683-
'key.key',
683+
`${name}.key`,
684684
getKeyTypes(ctx !== kCreatePrivate),
685685
data);
686686
}
687687

688688
const isPublic =
689689
(ctx === kConsumePrivate || ctx === kCreatePrivate) ? false : undefined;
690690
return {
691-
data: getArrayBufferOrView(data, 'key', encoding),
691+
data: getArrayBufferOrView(data, `${name}.key`, encoding),
692692
...parseKeyEncoding(key, undefined, isPublic),
693693
};
694694
}
695695

696696
throw new ERR_INVALID_ARG_TYPE(
697-
'key',
697+
name,
698698
getKeyTypes(ctx !== kCreatePrivate),
699699
key);
700700
}
701701

702-
function preparePrivateKey(key) {
703-
return prepareAsymmetricKey(key, kConsumePrivate);
702+
function preparePrivateKey(key, name) {
703+
return prepareAsymmetricKey(key, kConsumePrivate, name);
704704
}
705705

706-
function preparePublicOrPrivateKey(key) {
707-
return prepareAsymmetricKey(key, kConsumePublic);
706+
function preparePublicOrPrivateKey(key, name) {
707+
return prepareAsymmetricKey(key, kConsumePublic, name);
708708
}
709709

710710
function prepareSecretKey(key, encoding, bufferOnly = false) {
Collapse file

‎lib/internal/crypto/sig.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/sig.js
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ Sign.prototype.sign = function sign(options, encoding) {
135135
throw new ERR_CRYPTO_SIGN_KEY_REQUIRED();
136136

137137
const { data, format, type, passphrase, namedCurve } =
138-
preparePrivateKey(options, true);
138+
preparePrivateKey(options);
139139

140140
// Options specific to RSA
141141
const rsaPadding = getPadding(options);
@@ -239,7 +239,7 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) {
239239
type,
240240
passphrase,
241241
namedCurve,
242-
} = preparePublicOrPrivateKey(options, true);
242+
} = preparePublicOrPrivateKey(options);
243243

244244
// Options specific to RSA
245245
const rsaPadding = getPadding(options);
Collapse file

‎src/crypto/crypto_dh.cc‎

Copy file name to clipboardExpand all lines: src/crypto/crypto_dh.cc
+8-12Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -477,20 +477,16 @@ Maybe<void> DHBitsTraits::AdditionalConfig(
477477
const FunctionCallbackInfo<Value>& args,
478478
unsigned int offset,
479479
DHBitsConfig* params) {
480-
CHECK(args[offset]->IsObject()); // public key
481-
CHECK(args[offset + 1]->IsObject()); // private key
480+
auto public_key = KeyObjectData::GetPublicOrPrivateKeyFromJs(args, &offset);
481+
if (!public_key) [[unlikely]]
482+
return Nothing<void>();
482483

483-
KeyObjectHandle* private_key;
484-
KeyObjectHandle* public_key;
484+
auto private_key = KeyObjectData::GetPrivateKeyFromJs(args, &offset, true);
485+
if (!private_key) [[unlikely]]
486+
return Nothing<void>();
485487

486-
ASSIGN_OR_RETURN_UNWRAP(&public_key, args[offset], Nothing<void>());
487-
ASSIGN_OR_RETURN_UNWRAP(&private_key, args[offset + 1], Nothing<void>());
488-
489-
CHECK(private_key->Data().GetKeyType() == kKeyTypePrivate);
490-
CHECK(public_key->Data().GetKeyType() != kKeyTypeSecret);
491-
492-
params->public_key = public_key->Data().addRef();
493-
params->private_key = private_key->Data().addRef();
488+
params->public_key = std::move(public_key);
489+
params->private_key = std::move(private_key);
494490

495491
return JustVoid();
496492
}

0 commit comments

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