Skip to content

Commit 073e84d

Browse 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

9 files changed

Lines changed: 364 additions & 198 deletions

File tree

‎doc/api/crypto.md‎

Lines changed: 12 additions & 3 deletions
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])`

‎lib/internal/crypto/diffiehellman.js‎

Lines 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(!(privateKeyinstanceofKeyObject))
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
thrownewERR_INVALID_ARG_VALUE('options.privateKey',privateKey);
289294

290-
if(!(publicKeyinstanceofKeyObject))
295+
if(publicKey==null)
291296
thrownewERR_INVALID_ARG_VALUE('options.publicKey',publicKey);
292297

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

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

301-
constprivateType=privateKey.asymmetricKeyType;
302-
constpublicType=publicKey.asymmetricKeyType;
303-
if(privateType!==publicType||!dhEnabledKeyTypes.has(privateType)){
304-
thrownewERR_CRYPTO_INCOMPATIBLE_KEY('key types for Diffie-Hellman',
305-
`${privateType} and ${publicType}`);
310+
if(isKeyObject(privateKey)&&isKeyObject(publicKey)){
311+
constprivateType=privateKey.asymmetricKeyType;
312+
constpublicType=publicKey.asymmetricKeyType;
313+
if(privateType!==publicType||!dhEnabledKeyTypes.has(privateType)){
314+
thrownewERR_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
constjob=newDHBitsJob(
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
throwlazyDOMException('Named curve mismatch','InvalidAccessError');
350385
}
351386

352-
constbits=awaitjobPromise(()=>newECDHBitsJob(
387+
constbits=awaitjobPromise(()=>newDHBitsJob(
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)

‎lib/internal/crypto/keys.js‎

Lines 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-
functionprepareAsymmetricKey(key,ctx){
631+
functionprepareAsymmetricKey(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(typeofkey==='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
}elseif(format==='raw-public'||format==='raw-private'||
660660
format==='raw-seed'){
661661
if(!isStringOrBuffer(data)){
662662
thrownewERR_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
constrawFormat=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
thrownewERR_INVALID_ARG_TYPE(
683-
'key.key',
683+
`${name}.key`,
684684
getKeyTypes(ctx!==kCreatePrivate),
685685
data);
686686
}
687687

688688
constisPublic=
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
thrownewERR_INVALID_ARG_TYPE(
697-
'key',
697+
name,
698698
getKeyTypes(ctx!==kCreatePrivate),
699699
key);
700700
}
701701

702-
functionpreparePrivateKey(key){
703-
returnprepareAsymmetricKey(key,kConsumePrivate);
702+
functionpreparePrivateKey(key,name){
703+
returnprepareAsymmetricKey(key,kConsumePrivate,name);
704704
}
705705

706-
functionpreparePublicOrPrivateKey(key){
707-
returnprepareAsymmetricKey(key,kConsumePublic);
706+
functionpreparePublicOrPrivateKey(key,name){
707+
returnprepareAsymmetricKey(key,kConsumePublic,name);
708708
}
709709

710710
functionprepareSecretKey(key,encoding,bufferOnly=false){

‎lib/internal/crypto/sig.js‎

Lines 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
thrownewERR_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
constrsaPadding=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
constrsaPadding=getPadding(options);

‎src/crypto/crypto_dh.cc‎

Lines 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
unsignedint 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
returnJustVoid();
496492
}

0 commit comments

Comments
 (0)