Coverage Report

Created: 2025-10-31 09:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/src/crypto/crypto_dh.cc
Line
Count
Source
1
#include "crypto/crypto_dh.h"
2
#include "async_wrap-inl.h"
3
#include "base_object-inl.h"
4
#include "crypto/crypto_keys.h"
5
#include "crypto/crypto_util.h"
6
#include "env-inl.h"
7
#include "memory_tracker-inl.h"
8
#include "ncrypto.h"
9
#include "node_errors.h"
10
#ifndef OPENSSL_IS_BORINGSSL
11
#include "openssl/bnerr.h"
12
#endif
13
#include "openssl/dh.h"
14
#include "threadpoolwork-inl.h"
15
#include "v8.h"
16
17
namespace node {
18
19
using ncrypto::BignumPointer;
20
using ncrypto::DataPointer;
21
using ncrypto::DHPointer;
22
using ncrypto::EVPKeyCtxPointer;
23
using ncrypto::EVPKeyPointer;
24
using v8::ArrayBuffer;
25
using v8::BackingStoreInitializationMode;
26
using v8::BackingStoreOnFailureMode;
27
using v8::ConstructorBehavior;
28
using v8::Context;
29
using v8::DontDelete;
30
using v8::FunctionCallback;
31
using v8::FunctionCallbackInfo;
32
using v8::FunctionTemplate;
33
using v8::Int32;
34
using v8::Isolate;
35
using v8::JustVoid;
36
using v8::Local;
37
using v8::Maybe;
38
using v8::MaybeLocal;
39
using v8::Nothing;
40
using v8::Object;
41
using v8::PropertyAttribute;
42
using v8::ReadOnly;
43
using v8::SideEffectType;
44
using v8::Signature;
45
using v8::String;
46
using v8::Value;
47
48
namespace crypto {
49
DiffieHellman::DiffieHellman(Environment* env, Local<Object> wrap, DHPointer dh)
50
0
    : BaseObject(env, wrap), dh_(std::move(dh)) {
51
0
  MakeWeak();
52
0
}
53
54
0
void DiffieHellman::MemoryInfo(MemoryTracker* tracker) const {
55
0
  tracker->TrackFieldWithSize("dh", dh_ ? kSizeOf_DH : 0);
56
0
}
57
58
namespace {
59
0
MaybeLocal<Value> DataPointerToBuffer(Environment* env, DataPointer&& data) {
60
0
  struct Flag {
61
0
    bool secure;
62
0
  };
63
#ifdef V8_ENABLE_SANDBOX
64
  auto backing = ArrayBuffer::NewBackingStore(
65
      env->isolate(),
66
      data.size(),
67
      BackingStoreInitializationMode::kUninitialized,
68
      BackingStoreOnFailureMode::kReturnNull);
69
  if (!backing) {
70
    THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
71
    return MaybeLocal<Value>();
72
  }
73
  if (data.size() > 0) {
74
    memcpy(backing->Data(), data.get(), data.size());
75
  }
76
#else
77
0
  auto backing = ArrayBuffer::NewBackingStore(
78
0
      data.get(),
79
0
      data.size(),
80
0
      [](void* data, size_t len, void* ptr) {
81
0
        std::unique_ptr<Flag> flag(static_cast<Flag*>(ptr));
82
0
        DataPointer free_me(data, len, flag->secure);
83
0
      },
84
0
      new Flag{data.isSecure()});
85
0
  data.release();
86
0
#endif  // V8_ENABLE_SANDBOX
87
88
0
  auto ab = ArrayBuffer::New(env->isolate(), std::move(backing));
89
0
  return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>());
90
0
}
91
92
0
void DiffieHellmanGroup(const FunctionCallbackInfo<Value>& args) {
93
0
  Environment* env = Environment::GetCurrent(args);
94
0
  CHECK_EQ(args.Length(), 1);
95
0
  THROW_AND_RETURN_IF_NOT_STRING(env, args[0], "Group name");
96
0
  const node::Utf8Value group_name(env->isolate(), args[0]);
97
98
0
  DHPointer dh = DHPointer::FromGroup(group_name.ToStringView());
99
0
  if (!dh) {
100
0
    return THROW_ERR_CRYPTO_UNKNOWN_DH_GROUP(env);
101
0
  }
102
103
0
  new DiffieHellman(env, args.This(), std::move(dh));
104
0
}
105
106
0
void New(const FunctionCallbackInfo<Value>& args) {
107
0
  Environment* env = Environment::GetCurrent(args);
108
109
0
  if (args.Length() != 2) {
110
0
    return THROW_ERR_MISSING_ARGS(env, "Constructor must have two arguments");
111
0
  }
112
113
0
  if (args[0]->IsInt32()) {
114
0
    int32_t bits = args[0].As<Int32>()->Value();
115
0
    if (bits < 2) {
116
0
#ifndef OPENSSL_IS_BORINGSSL
117
0
#if OPENSSL_VERSION_MAJOR >= 3
118
0
      ERR_put_error(ERR_LIB_DH, 0, DH_R_MODULUS_TOO_SMALL, __FILE__, __LINE__);
119
#else
120
      ERR_put_error(ERR_LIB_BN, 0, BN_R_BITS_TOO_SMALL, __FILE__, __LINE__);
121
#endif  // OPENSSL_VERSION_MAJOR >= 3
122
#else   // OPENSSL_IS_BORINGSSL
123
      OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL);
124
#endif  // OPENSSL_IS_BORINGSSL
125
0
      return ThrowCryptoError(env, ERR_get_error(), "Invalid prime length");
126
0
    }
127
128
    // If the first argument is an Int32 then we are generating a new
129
    // prime and then using that to generate the Diffie-Hellman parameters.
130
    // The second argument must be an Int32 as well.
131
0
    if (!args[1]->IsInt32()) {
132
0
      return THROW_ERR_INVALID_ARG_TYPE(env,
133
0
                                        "Second argument must be an int32");
134
0
    }
135
0
    int32_t generator = args[1].As<Int32>()->Value();
136
0
    if (generator < 2) {
137
0
#ifndef OPENSSL_IS_BORINGSSL
138
0
      ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);
139
#else
140
      OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
141
#endif
142
0
      return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");
143
0
    }
144
145
0
    auto dh = DHPointer::New(bits, generator);
146
0
    if (!dh) {
147
0
      return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid DH parameters");
148
0
    }
149
0
    new DiffieHellman(env, args.This(), std::move(dh));
150
0
    return;
151
0
  }
152
153
  // The first argument must be an ArrayBuffer or ArrayBufferView with the
154
  // prime, and the second argument must be an int32 with the generator
155
  // or an ArrayBuffer or ArrayBufferView with the generator.
156
157
0
  ArrayBufferOrViewContents<char> arg0(args[0]);
158
0
  if (!arg0.CheckSizeInt32()) [[unlikely]]
159
0
    return THROW_ERR_OUT_OF_RANGE(env, "prime is too big");
160
161
0
  BignumPointer bn_p(reinterpret_cast<uint8_t*>(arg0.data()), arg0.size());
162
0
  BignumPointer bn_g;
163
0
  if (!bn_p) {
164
0
    return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid prime");
165
0
  }
166
167
0
  if (args[1]->IsInt32()) {
168
0
    int32_t generator = args[1].As<Int32>()->Value();
169
0
    if (generator < 2) {
170
0
#ifndef OPENSSL_IS_BORINGSSL
171
0
      ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);
172
#else
173
      OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
174
#endif
175
0
      return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");
176
0
    }
177
0
    bn_g = BignumPointer::New();
178
0
    if (!bn_g.setWord(generator)) {
179
0
#ifndef OPENSSL_IS_BORINGSSL
180
0
      ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);
181
#else
182
      OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
183
#endif
184
0
      return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");
185
0
    }
186
0
  } else {
187
0
    ArrayBufferOrViewContents<char> arg1(args[1]);
188
0
    if (!arg1.CheckSizeInt32()) [[unlikely]]
189
0
      return THROW_ERR_OUT_OF_RANGE(env, "generator is too big");
190
0
    bn_g = BignumPointer(reinterpret_cast<uint8_t*>(arg1.data()), arg1.size());
191
0
    if (!bn_g) {
192
0
#ifndef OPENSSL_IS_BORINGSSL
193
0
      ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);
194
#else
195
      OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
196
#endif
197
0
      return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");
198
0
    }
199
0
    if (bn_g.getWord() < 2) {
200
0
#ifndef OPENSSL_IS_BORINGSSL
201
0
      ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__);
202
#else
203
      OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR);
204
#endif
205
0
      return ThrowCryptoError(env, ERR_get_error(), "Invalid generator");
206
0
    }
207
0
  }
208
209
0
  auto dh = DHPointer::New(std::move(bn_p), std::move(bn_g));
210
0
  if (!dh) {
211
0
    return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid DH parameters");
212
0
  }
213
0
  new DiffieHellman(env, args.This(), std::move(dh));
214
0
}
215
216
0
void GenerateKeys(const FunctionCallbackInfo<Value>& args) {
217
0
  Environment* env = Environment::GetCurrent(args);
218
0
  DiffieHellman* diffieHellman;
219
0
  ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
220
0
  DHPointer& dh = *diffieHellman;
221
222
0
  auto dp = dh.generateKeys();
223
0
  if (!dp) {
224
0
    return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Key generation failed");
225
0
  }
226
227
0
  Local<Value> buffer;
228
0
  if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) {
229
0
    args.GetReturnValue().Set(buffer);
230
0
  }
231
0
}
232
233
0
void GetPrime(const FunctionCallbackInfo<Value>& args) {
234
0
  Environment* env = Environment::GetCurrent(args);
235
0
  DiffieHellman* diffieHellman;
236
0
  ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
237
0
  DHPointer& dh = *diffieHellman;
238
239
0
  auto dp = dh.getPrime();
240
0
  if (!dp) {
241
0
    return THROW_ERR_CRYPTO_INVALID_STATE(env, "p is null");
242
0
  }
243
0
  Local<Value> buffer;
244
0
  if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) {
245
0
    args.GetReturnValue().Set(buffer);
246
0
  }
247
0
}
248
249
0
void GetGenerator(const FunctionCallbackInfo<Value>& args) {
250
0
  Environment* env = Environment::GetCurrent(args);
251
0
  DiffieHellman* diffieHellman;
252
0
  ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
253
0
  DHPointer& dh = *diffieHellman;
254
255
0
  auto dp = dh.getGenerator();
256
0
  if (!dp) {
257
0
    return THROW_ERR_CRYPTO_INVALID_STATE(env, "g is null");
258
0
  }
259
0
  Local<Value> buffer;
260
0
  if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) {
261
0
    args.GetReturnValue().Set(buffer);
262
0
  }
263
0
}
264
265
0
void GetPublicKey(const FunctionCallbackInfo<Value>& args) {
266
0
  Environment* env = Environment::GetCurrent(args);
267
0
  DiffieHellman* diffieHellman;
268
0
  ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
269
0
  DHPointer& dh = *diffieHellman;
270
271
0
  auto dp = dh.getPublicKey();
272
0
  if (!dp) {
273
0
    return THROW_ERR_CRYPTO_INVALID_STATE(
274
0
        env, "No public key - did you forget to generate one?");
275
0
  }
276
0
  Local<Value> buffer;
277
0
  if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) {
278
0
    args.GetReturnValue().Set(buffer);
279
0
  }
280
0
}
281
282
0
void GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
283
0
  Environment* env = Environment::GetCurrent(args);
284
0
  DiffieHellman* diffieHellman;
285
0
  ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
286
0
  DHPointer& dh = *diffieHellman;
287
288
0
  auto dp = dh.getPrivateKey();
289
0
  if (!dp) {
290
0
    return THROW_ERR_CRYPTO_INVALID_STATE(
291
0
        env, "No private key - did you forget to generate one?");
292
0
  }
293
0
  Local<Value> buffer;
294
0
  if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) {
295
0
    args.GetReturnValue().Set(buffer);
296
0
  }
297
0
}
298
299
0
void ComputeSecret(const FunctionCallbackInfo<Value>& args) {
300
0
  Environment* env = Environment::GetCurrent(args);
301
0
  DiffieHellman* diffieHellman;
302
0
  ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
303
0
  DHPointer& dh = *diffieHellman;
304
305
0
  CHECK_EQ(args.Length(), 1);
306
0
  ArrayBufferOrViewContents<unsigned char> key_buf(args[0]);
307
0
  if (!key_buf.CheckSizeInt32()) [[unlikely]]
308
0
    return THROW_ERR_OUT_OF_RANGE(env, "secret is too big");
309
0
  BignumPointer key(key_buf.data(), key_buf.size());
310
311
0
  switch (dh.checkPublicKey(key)) {
312
0
    case DHPointer::CheckPublicKeyResult::INVALID:
313
      // Fall-through
314
0
    case DHPointer::CheckPublicKeyResult::CHECK_FAILED:
315
0
      return THROW_ERR_CRYPTO_INVALID_KEYTYPE(env,
316
0
                                              "Unspecified validation error");
317
0
    case DHPointer::CheckPublicKeyResult::TOO_SMALL:
318
0
      return THROW_ERR_CRYPTO_INVALID_KEYLEN(env, "Supplied key is too small");
319
0
    case DHPointer::CheckPublicKeyResult::TOO_LARGE:
320
0
      return THROW_ERR_CRYPTO_INVALID_KEYLEN(env, "Supplied key is too large");
321
0
    case DHPointer::CheckPublicKeyResult::NONE:
322
0
      break;
323
0
  }
324
325
0
  auto dp = dh.computeSecret(key);
326
327
0
  Local<Value> buffer;
328
0
  if (DataPointerToBuffer(env, std::move(dp)).ToLocal(&buffer)) {
329
0
    args.GetReturnValue().Set(buffer);
330
0
  }
331
0
}
332
333
0
void SetPublicKey(const FunctionCallbackInfo<Value>& args) {
334
0
  Environment* env = Environment::GetCurrent(args);
335
0
  DiffieHellman* diffieHellman;
336
0
  ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
337
0
  DHPointer& dh = *diffieHellman;
338
0
  CHECK_EQ(args.Length(), 1);
339
0
  ArrayBufferOrViewContents<unsigned char> buf(args[0]);
340
0
  if (!buf.CheckSizeInt32()) [[unlikely]]
341
0
    return THROW_ERR_OUT_OF_RANGE(env, "buf is too big");
342
0
  BignumPointer num(buf.data(), buf.size());
343
0
  CHECK(num);
344
0
  CHECK(dh.setPublicKey(std::move(num)));
345
0
}
346
347
0
void SetPrivateKey(const FunctionCallbackInfo<Value>& args) {
348
0
  Environment* env = Environment::GetCurrent(args);
349
0
  DiffieHellman* diffieHellman;
350
0
  ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
351
0
  DHPointer& dh = *diffieHellman;
352
0
  CHECK_EQ(args.Length(), 1);
353
0
  ArrayBufferOrViewContents<unsigned char> buf(args[0]);
354
0
  if (!buf.CheckSizeInt32()) [[unlikely]]
355
0
    return THROW_ERR_OUT_OF_RANGE(env, "buf is too big");
356
0
  BignumPointer num(buf.data(), buf.size());
357
0
  CHECK(num);
358
0
  CHECK(dh.setPrivateKey(std::move(num)));
359
0
}
360
361
0
void Check(const FunctionCallbackInfo<Value>& args) {
362
0
  Environment* env = Environment::GetCurrent(args);
363
0
  DiffieHellman* diffieHellman;
364
0
  ASSIGN_OR_RETURN_UNWRAP(&diffieHellman, args.This());
365
366
0
  DHPointer& dh = *diffieHellman;
367
0
  auto result = dh.check();
368
0
  if (result == DHPointer::CheckResult::CHECK_FAILED) {
369
0
    return THROW_ERR_CRYPTO_OPERATION_FAILED(env,
370
0
                                             "Checking DH parameters failed");
371
0
  }
372
373
0
  args.GetReturnValue().Set(static_cast<int>(result));
374
0
}
375
376
}  // namespace
377
378
// The input arguments to DhKeyPairGenJob can vary
379
//   1. CryptoJobMode
380
// and either
381
//   2. Group name (as a string)
382
// or
383
//   2. Prime or Prime Length
384
//   3. Generator
385
// Followed by the public and private key encoding parameters:
386
//   * Public format
387
//   * Public type
388
//   * Private format
389
//   * Private type
390
//   * Cipher
391
//   * Passphrase
392
Maybe<void> DhKeyGenTraits::AdditionalConfig(
393
    CryptoJobMode mode,
394
    const FunctionCallbackInfo<Value>& args,
395
    unsigned int* offset,
396
0
    DhKeyPairGenConfig* params) {
397
0
  Environment* env = Environment::GetCurrent(args);
398
399
0
  if (args[*offset]->IsString()) {
400
0
    Utf8Value group_name(env->isolate(), args[*offset]);
401
0
    auto group = DHPointer::FindGroup(group_name.ToStringView());
402
0
    if (!group) {
403
0
      THROW_ERR_CRYPTO_UNKNOWN_DH_GROUP(env);
404
0
      return Nothing<void>();
405
0
    }
406
407
0
    static constexpr int kStandardizedGenerator = 2;
408
409
0
    params->params.prime = std::move(group);
410
0
    params->params.generator = kStandardizedGenerator;
411
0
    *offset += 1;
412
0
  } else {
413
0
    if (args[*offset]->IsInt32()) {
414
0
      int size = args[*offset].As<Int32>()->Value();
415
0
      if (size < 0) {
416
0
        THROW_ERR_OUT_OF_RANGE(env, "Invalid prime size");
417
0
        return Nothing<void>();
418
0
      }
419
0
      params->params.prime = size;
420
0
    } else {
421
0
      ArrayBufferOrViewContents<unsigned char> input(args[*offset]);
422
0
      if (!input.CheckSizeInt32()) [[unlikely]] {
423
0
        THROW_ERR_OUT_OF_RANGE(env, "prime is too big");
424
0
        return Nothing<void>();
425
0
      }
426
0
      params->params.prime = BignumPointer(input.data(), input.size());
427
0
    }
428
429
0
    CHECK(args[*offset + 1]->IsInt32());
430
0
    params->params.generator = args[*offset + 1].As<Int32>()->Value();
431
0
    *offset += 2;
432
0
  }
433
434
0
  return JustVoid();
435
0
}
436
437
0
EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) {
438
0
  EVPKeyPointer key_params;
439
0
  if (BignumPointer* prime_fixed_value =
440
0
          std::get_if<BignumPointer>(&params->params.prime)) {
441
0
    auto prime = prime_fixed_value->clone();
442
0
    auto bn_g = BignumPointer::New();
443
0
    if (!prime || !bn_g || !bn_g.setWord(params->params.generator)) {
444
0
      return {};
445
0
    }
446
0
    auto dh = DHPointer::New(std::move(prime), std::move(bn_g));
447
0
    if (!dh) return {};
448
449
0
    key_params = EVPKeyPointer::NewDH(std::move(dh));
450
0
  } else if (std::get_if<int>(&params->params.prime)) {
451
0
    auto param_ctx = EVPKeyCtxPointer::NewFromID(EVP_PKEY_DH);
452
0
#ifndef OPENSSL_IS_BORINGSSL
453
0
    int* prime_size = std::get_if<int>(&params->params.prime);
454
0
    if (!param_ctx.initForParamgen() ||
455
0
        !param_ctx.setDhParameters(*prime_size, params->params.generator)) {
456
0
      return {};
457
0
    }
458
459
0
    key_params = param_ctx.paramgen();
460
#else
461
    return {};
462
#endif
463
0
  } else {
464
0
    UNREACHABLE();
465
0
  }
466
467
0
  if (!key_params) return {};
468
469
0
  EVPKeyCtxPointer ctx = key_params.newCtx();
470
0
  if (!ctx.initForKeygen()) return {};
471
472
0
  return ctx;
473
0
}
474
475
Maybe<void> DHKeyExportTraits::AdditionalConfig(
476
    const FunctionCallbackInfo<Value>& args,
477
    unsigned int offset,
478
0
    DHKeyExportConfig* params) {
479
0
  return JustVoid();
480
0
}
481
482
WebCryptoKeyExportStatus DHKeyExportTraits::DoExport(
483
    const KeyObjectData& key_data,
484
    WebCryptoKeyFormat format,
485
    const DHKeyExportConfig& params,
486
0
    ByteSource* out) {
487
0
  CHECK_NE(key_data.GetKeyType(), kKeyTypeSecret);
488
489
0
  switch (format) {
490
0
    case kWebCryptoKeyFormatPKCS8:
491
0
      if (key_data.GetKeyType() != kKeyTypePrivate)
492
0
        return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
493
0
      return PKEY_PKCS8_Export(key_data, out);
494
0
    case kWebCryptoKeyFormatSPKI:
495
0
      if (key_data.GetKeyType() != kKeyTypePublic)
496
0
        return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
497
0
      return PKEY_SPKI_Export(key_data, out);
498
0
    default:
499
0
      UNREACHABLE();
500
0
  }
501
0
}
502
503
Maybe<void> DHBitsTraits::AdditionalConfig(
504
    CryptoJobMode mode,
505
    const FunctionCallbackInfo<Value>& args,
506
    unsigned int offset,
507
0
    DHBitsConfig* params) {
508
0
  CHECK(args[offset]->IsObject());  // public key
509
0
  CHECK(args[offset + 1]->IsObject());  // private key
510
511
0
  KeyObjectHandle* private_key;
512
0
  KeyObjectHandle* public_key;
513
514
0
  ASSIGN_OR_RETURN_UNWRAP(&public_key, args[offset], Nothing<void>());
515
0
  ASSIGN_OR_RETURN_UNWRAP(&private_key, args[offset + 1], Nothing<void>());
516
517
0
  CHECK(private_key->Data().GetKeyType() == kKeyTypePrivate);
518
0
  CHECK(public_key->Data().GetKeyType() != kKeyTypeSecret);
519
520
0
  params->public_key = public_key->Data().addRef();
521
0
  params->private_key = private_key->Data().addRef();
522
523
0
  return JustVoid();
524
0
}
525
526
MaybeLocal<Value> DHBitsTraits::EncodeOutput(Environment* env,
527
                                             const DHBitsConfig& params,
528
0
                                             ByteSource* out) {
529
0
  return out->ToArrayBuffer(env);
530
0
}
531
532
bool DHBitsTraits::DeriveBits(Environment* env,
533
                              const DHBitsConfig& params,
534
                              ByteSource* out,
535
0
                              CryptoJobMode mode) {
536
0
  auto dp = DHPointer::stateless(params.private_key.GetAsymmetricKey(),
537
0
                                 params.public_key.GetAsymmetricKey());
538
0
  if (!dp) {
539
0
    bool can_throw = mode == CryptoJobMode::kCryptoJobSync;
540
541
0
    if (can_throw) {
542
0
      unsigned long err = ERR_get_error();  // NOLINT(runtime/int)
543
0
      if (err) ThrowCryptoError(env, err, "diffieHellman failed");
544
0
    }
545
0
    return false;
546
0
  }
547
548
0
  *out = ByteSource::Allocated(dp.release());
549
0
  CHECK(!out->empty());
550
0
  return true;
551
0
}
552
553
bool GetDhKeyDetail(Environment* env,
554
                    const KeyObjectData& key,
555
0
                    Local<Object> target) {
556
0
  CHECK_EQ(key.GetAsymmetricKey().id(), EVP_PKEY_DH);
557
0
  return true;
558
0
}
559
560
0
void DiffieHellman::Initialize(Environment* env, Local<Object> target) {
561
0
  Isolate* isolate = env->isolate();
562
0
  Local<Context> context = env->context();
563
0
  auto make = [&](Local<String> name, FunctionCallback callback) {
564
0
    Local<FunctionTemplate> t = NewFunctionTemplate(isolate, callback);
565
566
0
    const PropertyAttribute attributes =
567
0
        static_cast<PropertyAttribute>(ReadOnly | DontDelete);
568
569
0
    t->InstanceTemplate()->SetInternalFieldCount(
570
0
        DiffieHellman::kInternalFieldCount);
571
572
0
    SetProtoMethod(isolate, t, "generateKeys", GenerateKeys);
573
0
    SetProtoMethod(isolate, t, "computeSecret", ComputeSecret);
574
0
    SetProtoMethodNoSideEffect(isolate, t, "getPrime", GetPrime);
575
0
    SetProtoMethodNoSideEffect(isolate, t, "getGenerator", GetGenerator);
576
0
    SetProtoMethodNoSideEffect(isolate, t, "getPublicKey", GetPublicKey);
577
0
    SetProtoMethodNoSideEffect(isolate, t, "getPrivateKey", GetPrivateKey);
578
0
    SetProtoMethod(isolate, t, "setPublicKey", SetPublicKey);
579
0
    SetProtoMethod(isolate, t, "setPrivateKey", SetPrivateKey);
580
581
0
    Local<FunctionTemplate> verify_error_getter_templ =
582
0
        FunctionTemplate::New(isolate,
583
0
                              Check,
584
0
                              Local<Value>(),
585
0
                              Signature::New(env->isolate(), t),
586
0
                              /* length */ 0,
587
0
                              ConstructorBehavior::kThrow,
588
0
                              SideEffectType::kHasNoSideEffect);
589
590
0
    t->InstanceTemplate()->SetAccessorProperty(env->verify_error_string(),
591
0
                                               verify_error_getter_templ,
592
0
                                               Local<FunctionTemplate>(),
593
0
                                               attributes);
594
595
0
    SetConstructorFunction(context, target, name, t);
596
0
  };
597
598
0
  make(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellman"), New);
599
0
  make(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellmanGroup"),
600
0
       DiffieHellmanGroup);
601
602
0
  DHKeyPairGenJob::Initialize(env, target);
603
0
  DHKeyExportJob::Initialize(env, target);
604
0
  DHBitsJob::Initialize(env, target);
605
0
}
606
607
void DiffieHellman::RegisterExternalReferences(
608
0
    ExternalReferenceRegistry* registry) {
609
0
  registry->Register(New);
610
0
  registry->Register(DiffieHellmanGroup);
611
612
0
  registry->Register(GenerateKeys);
613
0
  registry->Register(ComputeSecret);
614
0
  registry->Register(GetPrime);
615
0
  registry->Register(GetGenerator);
616
0
  registry->Register(GetPublicKey);
617
0
  registry->Register(GetPrivateKey);
618
0
  registry->Register(SetPublicKey);
619
0
  registry->Register(SetPrivateKey);
620
621
0
  registry->Register(Check);
622
623
0
  DHKeyPairGenJob::RegisterExternalReferences(registry);
624
0
  DHKeyExportJob::RegisterExternalReferences(registry);
625
0
  DHBitsJob::RegisterExternalReferences(registry);
626
0
}
627
628
}  // namespace crypto
629
}  // namespace node