GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_util.h Lines: 233 242 96.3 %
Date: 2022-05-21 04:15:56 Branches: 80 119 67.2 %

Line Branch Exec Source
1
#ifndef SRC_CRYPTO_CRYPTO_UTIL_H_
2
#define SRC_CRYPTO_CRYPTO_UTIL_H_
3
4
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5
6
#include "async_wrap.h"
7
#include "env.h"
8
#include "node_errors.h"
9
#include "node_external_reference.h"
10
#include "node_internals.h"
11
#include "string_bytes.h"
12
#include "util.h"
13
#include "v8.h"
14
15
#include <openssl/err.h>
16
#include <openssl/evp.h>
17
#include <openssl/ec.h>
18
#include <openssl/kdf.h>
19
#include <openssl/rsa.h>
20
#include <openssl/dsa.h>
21
#include <openssl/ssl.h>
22
#ifndef OPENSSL_NO_ENGINE
23
#  include <openssl/engine.h>
24
#endif  // !OPENSSL_NO_ENGINE
25
// The FIPS-related functions are only available
26
// when the OpenSSL itself was compiled with FIPS support.
27
#if defined(OPENSSL_FIPS) && OPENSSL_VERSION_MAJOR < 3
28
#  include <openssl/fips.h>
29
#endif  // OPENSSL_FIPS
30
31
#include <algorithm>
32
#include <memory>
33
#include <string>
34
#include <vector>
35
#include <climits>
36
#include <cstdio>
37
38
namespace node {
39
namespace crypto {
40
// Currently known sizes of commonly used OpenSSL struct sizes.
41
// OpenSSL considers it's various structs to be opaque and the
42
// sizes may change from one version of OpenSSL to another, so
43
// these values should not be trusted to remain static. These
44
// are provided to allow for some close to reasonable memory
45
// tracking.
46
constexpr size_t kSizeOf_DH = 144;
47
constexpr size_t kSizeOf_EC_KEY = 80;
48
constexpr size_t kSizeOf_EVP_CIPHER_CTX = 168;
49
constexpr size_t kSizeOf_EVP_MD_CTX = 48;
50
constexpr size_t kSizeOf_EVP_PKEY = 72;
51
constexpr size_t kSizeOf_EVP_PKEY_CTX = 80;
52
constexpr size_t kSizeOf_HMAC_CTX = 32;
53
54
// Define smart pointers for the most commonly used OpenSSL types:
55
using X509Pointer = DeleteFnPtr<X509, X509_free>;
56
using BIOPointer = DeleteFnPtr<BIO, BIO_free_all>;
57
using SSLCtxPointer = DeleteFnPtr<SSL_CTX, SSL_CTX_free>;
58
using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>;
59
using SSLPointer = DeleteFnPtr<SSL, SSL_free>;
60
using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
61
using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>;
62
using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
63
using EVPMDPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
64
using RSAPointer = DeleteFnPtr<RSA, RSA_free>;
65
using ECPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
66
using BignumPointer = DeleteFnPtr<BIGNUM, BN_free>;
67
using BignumCtxPointer = DeleteFnPtr<BN_CTX, BN_CTX_free>;
68
using NetscapeSPKIPointer = DeleteFnPtr<NETSCAPE_SPKI, NETSCAPE_SPKI_free>;
69
using ECGroupPointer = DeleteFnPtr<EC_GROUP, EC_GROUP_free>;
70
using ECPointPointer = DeleteFnPtr<EC_POINT, EC_POINT_free>;
71
using ECKeyPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
72
using DHPointer = DeleteFnPtr<DH, DH_free>;
73
using ECDSASigPointer = DeleteFnPtr<ECDSA_SIG, ECDSA_SIG_free>;
74
using HMACCtxPointer = DeleteFnPtr<HMAC_CTX, HMAC_CTX_free>;
75
using CipherCtxPointer = DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>;
76
using RsaPointer = DeleteFnPtr<RSA, RSA_free>;
77
using DsaPointer = DeleteFnPtr<DSA, DSA_free>;
78
using DsaSigPointer = DeleteFnPtr<DSA_SIG, DSA_SIG_free>;
79
80
// Our custom implementation of the certificate verify callback
81
// used when establishing a TLS handshake. Because we cannot perform
82
// I/O quickly enough with X509_STORE_CTX_ APIs in this callback,
83
// we ignore preverify_ok errors here and let the handshake continue.
84
// In other words, this VerifyCallback is a non-op. It is imperative
85
// that the user user Connection::VerifyError after the `secure`
86
// callback has been made.
87
extern int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx);
88
89
bool ProcessFipsOptions();
90
91
bool InitCryptoOnce(v8::Isolate* isolate);
92
void InitCryptoOnce();
93
94
void InitCrypto(v8::Local<v8::Object> target);
95
96
extern void UseExtraCaCerts(const std::string& file);
97
98
// Forcibly clear OpenSSL's error stack on return. This stops stale errors
99
// from popping up later in the lifecycle of crypto operations where they
100
// would cause spurious failures. It's a rather blunt method, though.
101
// ERR_clear_error() isn't necessarily cheap either.
102
struct ClearErrorOnReturn {
103
11672
  ~ClearErrorOnReturn() { ERR_clear_error(); }
104
};
105
106
// Pop errors from OpenSSL's error stack that were added
107
// between when this was constructed and destructed.
108
struct MarkPopErrorOnReturn {
109
23390
  MarkPopErrorOnReturn() { ERR_set_mark(); }
110
23389
  ~MarkPopErrorOnReturn() { ERR_pop_to_mark(); }
111
};
112
113
// Ensure that OpenSSL has enough entropy (at least 256 bits) for its PRNG.
114
// The entropy pool starts out empty and needs to fill up before the PRNG
115
// can be used securely.  Once the pool is filled, it never dries up again;
116
// its contents is stirred and reused when necessary.
117
//
118
// OpenSSL normally fills the pool automatically but not when someone starts
119
// generating random numbers before the pool is full: in that case OpenSSL
120
// keeps lowering the entropy estimate to thwart attackers trying to guess
121
// the initial state of the PRNG.
122
//
123
// When that happens, we will have to wait until enough entropy is available.
124
// That should normally never take longer than a few milliseconds.
125
//
126
// OpenSSL draws from /dev/random and /dev/urandom.  While /dev/random may
127
// block pending "true" randomness, /dev/urandom is a CSPRNG that doesn't
128
// block under normal circumstances.
129
//
130
// The only time when /dev/urandom may conceivably block is right after boot,
131
// when the whole system is still low on entropy.  That's not something we can
132
// do anything about.
133
void CheckEntropy();
134
135
// Generate length bytes of random data. If this returns false, the data
136
// may not be truly random but it's still generally good enough.
137
bool EntropySource(unsigned char* buffer, size_t length);
138
139
int PasswordCallback(char* buf, int size, int rwflag, void* u);
140
141
int NoPasswordCallback(char* buf, int size, int rwflag, void* u);
142
143
// Decode is used by the various stream-based crypto utilities to decode
144
// string input.
145
template <typename T>
146
3710
void Decode(const v8::FunctionCallbackInfo<v8::Value>& args,
147
            void (*callback)(T*, const v8::FunctionCallbackInfo<v8::Value>&,
148
                             const char*, size_t)) {
149
  T* ctx;
150
3710
  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
151
152
7420
  if (args[0]->IsString()) {
153
1838
    StringBytes::InlineDecoder decoder;
154
1838
    Environment* env = Environment::GetCurrent(args);
155
1838
    enum encoding enc = ParseEncoding(env->isolate(), args[1], UTF8);
156
5514
    if (decoder.Decode(env, args[0].As<v8::String>(), enc).IsNothing())
157
      return;
158
1838
    callback(ctx, args, decoder.out(), decoder.size());
159
  } else {
160
1872
    ArrayBufferViewContents<char> buf(args[0]);
161
1872
    callback(ctx, args, buf.data(), buf.length());
162
  }
163
}
164
165
#define NODE_CRYPTO_ERROR_CODES_MAP(V)                                        \
166
    V(CIPHER_JOB_FAILED, "Cipher job failed")                                 \
167
    V(DERIVING_BITS_FAILED, "Deriving bits failed")                           \
168
    V(ENGINE_NOT_FOUND, "Engine \"%s\" was not found")                        \
169
    V(INVALID_KEY_TYPE, "Invalid key type")                                   \
170
    V(KEY_GENERATION_JOB_FAILED, "Key generation job failed")                 \
171
    V(OK, "Ok")                                                               \
172
173
enum class NodeCryptoError {
174
#define V(CODE, DESCRIPTION) CODE,
175
  NODE_CRYPTO_ERROR_CODES_MAP(V)
176
#undef V
177
};
178
179
// Utility struct used to harvest error information from openssl's error stack
180
struct CryptoErrorStore final : public MemoryRetainer {
181
 public:
182
  void Capture();
183
184
  bool Empty() const;
185
186
  template <typename... Args>
187
  void Insert(const NodeCryptoError error, Args&&... args);
188
189
  v8::MaybeLocal<v8::Value> ToException(
190
      Environment* env,
191
      v8::Local<v8::String> exception_string = v8::Local<v8::String>()) const;
192
193
3
  SET_NO_MEMORY_INFO()
194
3
  SET_MEMORY_INFO_NAME(CryptoErrorStore)
195
3
  SET_SELF_SIZE(CryptoErrorStore)
196
197
 private:
198
  std::vector<std::string> errors_;
199
};
200
201
template <typename... Args>
202
14
void CryptoErrorStore::Insert(const NodeCryptoError error, Args&&... args) {
203
14
  const char* error_string = nullptr;
204

14
  switch (error) {
205
#define V(CODE, DESCRIPTION) \
206
    case NodeCryptoError::CODE: error_string = DESCRIPTION; break;
207
14
    NODE_CRYPTO_ERROR_CODES_MAP(V)
208
#undef V
209
  }
210
14
  errors_.emplace_back(SPrintF(error_string,
211
                               std::forward<Args>(args)...));
212
14
}
213
214
template <typename T>
215
15740
T* MallocOpenSSL(size_t count) {
216
15740
  void* mem = OPENSSL_malloc(MultiplyWithOverflowCheck(count, sizeof(T)));
217

15740
  CHECK_IMPLIES(mem == nullptr, count == 0);
218
15740
  return static_cast<T*>(mem);
219
}
220
221
template <typename T>
222
1419
T* ReallocOpenSSL(T* buf, size_t count) {
223
1419
  void* mem = OPENSSL_realloc(buf, MultiplyWithOverflowCheck(count, sizeof(T)));
224

1419
  CHECK_IMPLIES(mem == nullptr, count == 0);
225
1419
  return static_cast<T*>(mem);
226
}
227
228
// A helper class representing a read-only byte array. When deallocated, its
229
// contents are zeroed.
230
class ByteSource {
231
 public:
232
21800
  ByteSource() = default;
233
  ByteSource(ByteSource&& other) noexcept;
234
  ~ByteSource();
235
236
  ByteSource& operator=(ByteSource&& other) noexcept;
237
238
  const char* get() const;
239
240
  template <typename T>
241
7087
  const T* data() const { return reinterpret_cast<const T*>(get()); }
242
243
  size_t size() const;
244
245
4523
  operator bool() const { return data_ != nullptr; }
246
247
2841
  BignumPointer ToBN() const {
248
    return BignumPointer(BN_bin2bn(
249
2841
        reinterpret_cast<const unsigned char*>(get()),
250
2841
        size(),
251
2841
        nullptr));
252
  }
253
254
  // Creates a v8::BackingStore that takes over responsibility for
255
  // any allocated data. The ByteSource will be reset with size = 0
256
  // after being called.
257
  std::unique_ptr<v8::BackingStore> ReleaseToBackingStore();
258
259
  v8::Local<v8::ArrayBuffer> ToArrayBuffer(Environment* env);
260
261
  v8::MaybeLocal<v8::Uint8Array> ToBuffer(Environment* env);
262
263
  void reset();
264
265
  // Allows an Allocated ByteSource to be truncated.
266
1419
  void Resize(size_t newsize) {
267
1419
    CHECK_LE(newsize, size_);
268
1419
    CHECK_NOT_NULL(allocated_data_);
269
1419
    char* new_data_ = ReallocOpenSSL<char>(allocated_data_, newsize);
270
1419
    data_ = allocated_data_ = new_data_;
271
1419
    size_ = newsize;
272
1419
  }
273
274
  static ByteSource Allocated(char* data, size_t size);
275
  static ByteSource Foreign(const char* data, size_t size);
276
277
  static ByteSource FromEncodedString(Environment* env,
278
                                      v8::Local<v8::String> value,
279
                                      enum encoding enc = BASE64);
280
281
  static ByteSource FromStringOrBuffer(Environment* env,
282
                                       v8::Local<v8::Value> value);
283
284
  static ByteSource FromString(Environment* env,
285
                               v8::Local<v8::String> str,
286
                               bool ntc = false);
287
288
  static ByteSource FromBuffer(v8::Local<v8::Value> buffer,
289
                               bool ntc = false);
290
291
  static ByteSource FromBIO(const BIOPointer& bio);
292
293
  static ByteSource NullTerminatedCopy(Environment* env,
294
                                       v8::Local<v8::Value> value);
295
296
  static ByteSource FromSymmetricKeyObjectHandle(v8::Local<v8::Value> handle);
297
298
  ByteSource(const ByteSource&) = delete;
299
  ByteSource& operator=(const ByteSource&) = delete;
300
301
  static ByteSource FromSecretKeyBytes(
302
      Environment* env, v8::Local<v8::Value> value);
303
304
 private:
305
  const char* data_ = nullptr;
306
  char* allocated_data_ = nullptr;
307
  size_t size_ = 0;
308
309
  ByteSource(const char* data, char* allocated_data, size_t size);
310
};
311
312
enum CryptoJobMode {
313
  kCryptoJobAsync,
314
  kCryptoJobSync
315
};
316
317
CryptoJobMode GetCryptoJobMode(v8::Local<v8::Value> args);
318
319
template <typename CryptoJobTraits>
320
class CryptoJob : public AsyncWrap, public ThreadPoolWork {
321
 public:
322
  using AdditionalParams = typename CryptoJobTraits::AdditionalParameters;
323
324
7706
  explicit CryptoJob(
325
      Environment* env,
326
      v8::Local<v8::Object> object,
327
      AsyncWrap::ProviderType type,
328
      CryptoJobMode mode,
329
      AdditionalParams&& params)
330
      : AsyncWrap(env, object, type),
331
        ThreadPoolWork(env),
332
        mode_(mode),
333
7706
        params_(std::move(params)) {
334
    // If the CryptoJob is async, then the instance will be
335
    // cleaned up when AfterThreadPoolWork is called.
336
7706
    if (mode == kCryptoJobSync) MakeWeak();
337
7706
  }
338
339
  bool IsNotIndicativeOfMemoryLeakAtExit() const override {
340
    // CryptoJobs run a work in the libuv thread pool and may still
341
    // exist when the event loop empties and starts to exit.
342
    return true;
343
  }
344
345
5889
  void AfterThreadPoolWork(int status) override {
346
5889
    Environment* env = AsyncWrap::env();
347
5889
    CHECK_EQ(mode_, kCryptoJobAsync);
348

5889
    CHECK(status == 0 || status == UV_ECANCELED);
349
5889
    std::unique_ptr<CryptoJob> ptr(this);
350
    // If the job was canceled do not execute the callback.
351
    // TODO(@jasnell): We should likely revisit skipping the
352
    // callback on cancel as that could leave the JS in a pending
353
    // state (e.g. unresolved promises...)
354
5889
    if (status == UV_ECANCELED) return;
355
5889
    v8::HandleScope handle_scope(env->isolate());
356
11778
    v8::Context::Scope context_scope(env->context());
357
358
    // TODO(tniessen): Remove the exception handling logic here as soon as we
359
    // can verify that no code path in ToResult will ever throw an exception.
360
    v8::Local<v8::Value> exception;
361
17667
    v8::Local<v8::Value> args[2];
362
    {
363
5889
      node::errors::TryCatchScope try_catch(env);
364
5889
      v8::Maybe<bool> ret = ptr->ToResult(&args[0], &args[1]);
365
5889
      if (!ret.IsJust()) {
366
4
        CHECK(try_catch.HasCaught());
367
4
        exception = try_catch.Exception();
368
5885
      } else if (!ret.FromJust()) {
369
        return;
370
      }
371
    }
372
373
5889
    if (exception.IsEmpty()) {
374
5885
      ptr->MakeCallback(env->ondone_string(), arraysize(args), args);
375
    } else {
376
4
      ptr->MakeCallback(env->ondone_string(), 1, &exception);
377
    }
378
  }
379
380
  virtual v8::Maybe<bool> ToResult(
381
      v8::Local<v8::Value>* err,
382
      v8::Local<v8::Value>* result) = 0;
383
384
7692
  CryptoJobMode mode() const { return mode_; }
385
386
7767
  CryptoErrorStore* errors() { return &errors_; }
387
388
12597
  AdditionalParams* params() { return &params_; }
389
390
6
  std::string MemoryInfoName() const override {
391
6
    return CryptoJobTraits::JobName;
392
  }
393
394
6
  void MemoryInfo(MemoryTracker* tracker) const override {
395
6
    tracker->TrackField("params", params_);
396
6
    tracker->TrackField("errors", errors_);
397
  }
398
399
7692
  static void Run(const v8::FunctionCallbackInfo<v8::Value>& args) {
400
7692
    Environment* env = Environment::GetCurrent(args);
401
402
    CryptoJob<CryptoJobTraits>* job;
403
13583
    ASSIGN_OR_RETURN_UNWRAP(&job, args.Holder());
404
7692
    if (job->mode() == kCryptoJobAsync)
405
5891
      return job->ScheduleWork();
406
407
5403
    v8::Local<v8::Value> ret[2];
408
1801
    env->PrintSyncTrace();
409
1801
    job->DoThreadPoolWork();
410
1801
    v8::Maybe<bool> result = job->ToResult(&ret[0], &ret[1]);
411

3596
    if (result.IsJust() && result.FromJust()) {
412
3590
      args.GetReturnValue().Set(
413
          v8::Array::New(env->isolate(), ret, arraysize(ret)));
414
    }
415
  }
416
417
35952
  static void Initialize(
418
      v8::FunctionCallback new_fn,
419
      Environment* env,
420
      v8::Local<v8::Object> target) {
421
35952
    v8::Local<v8::FunctionTemplate> job = env->NewFunctionTemplate(new_fn);
422
35952
    job->Inherit(AsyncWrap::GetConstructorTemplate(env));
423
71904
    job->InstanceTemplate()->SetInternalFieldCount(
424
        AsyncWrap::kInternalFieldCount);
425
35952
    env->SetProtoMethod(job, "run", Run);
426
35952
    env->SetConstructorFunction(target, CryptoJobTraits::JobName, job);
427
35952
  }
428
429
217728
  static void RegisterExternalReferences(v8::FunctionCallback new_fn,
430
                                         ExternalReferenceRegistry* registry) {
431
217728
    registry->Register(new_fn);
432
217728
    registry->Register(Run);
433
217728
  }
434
435
 private:
436
  const CryptoJobMode mode_;
437
  CryptoErrorStore errors_;
438
  AdditionalParams params_;
439
};
440
441
template <typename DeriveBitsTraits>
442
class DeriveBitsJob final : public CryptoJob<DeriveBitsTraits> {
443
 public:
444
  using AdditionalParams = typename DeriveBitsTraits::AdditionalParameters;
445
446
3919
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
447
3919
    Environment* env = Environment::GetCurrent(args);
448
449
3919
    CryptoJobMode mode = GetCryptoJobMode(args[0]);
450
451
3919
    AdditionalParams params;
452
7838
    if (DeriveBitsTraits::AdditionalConfig(mode, args, 1, &params)
453
            .IsNothing()) {
454
      // The DeriveBitsTraits::AdditionalConfig is responsible for
455
      // calling an appropriate THROW_CRYPTO_* variant reporting
456
      // whatever error caused initialization to fail.
457
73
      return;
458
    }
459
460
3846
    new DeriveBitsJob(env, args.This(), mode, std::move(params));
461
  }
462
463
14552
  static void Initialize(
464
      Environment* env,
465
      v8::Local<v8::Object> target) {
466
14552
    CryptoJob<DeriveBitsTraits>::Initialize(New, env, target);
467
14552
  }
468
469
88128
  static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
470
88128
    CryptoJob<DeriveBitsTraits>::RegisterExternalReferences(New, registry);
471
88128
  }
472
473
3846
  DeriveBitsJob(
474
      Environment* env,
475
      v8::Local<v8::Object> object,
476
      CryptoJobMode mode,
477
      AdditionalParams&& params)
478
      : CryptoJob<DeriveBitsTraits>(
479
            env,
480
            object,
481
            DeriveBitsTraits::Provider,
482
            mode,
483
3846
            std::move(params)) {}
484
485
3846
  void DoThreadPoolWork() override {
486
3846
    if (!DeriveBitsTraits::DeriveBits(
487
            AsyncWrap::env(),
488
3846
            *CryptoJob<DeriveBitsTraits>::params(), &out_)) {
489
14
      CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors();
490
14
      errors->Capture();
491
14
      if (errors->Empty())
492
14
        errors->Insert(NodeCryptoError::DERIVING_BITS_FAILED);
493
14
      return;
494
    }
495
3832
    success_ = true;
496
  }
497
498
3846
  v8::Maybe<bool> ToResult(
499
      v8::Local<v8::Value>* err,
500
      v8::Local<v8::Value>* result) override {
501
3846
    Environment* env = AsyncWrap::env();
502
3846
    CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors();
503
3846
    if (success_) {
504
3832
      CHECK(errors->Empty());
505
3832
      *err = v8::Undefined(env->isolate());
506
3832
      return DeriveBitsTraits::EncodeOutput(
507
          env,
508
3832
          *CryptoJob<DeriveBitsTraits>::params(),
509
          &out_,
510
3832
          result);
511
    }
512
513
14
    if (errors->Empty())
514
      errors->Capture();
515
14
    CHECK(!errors->Empty());
516
28
    *result = v8::Undefined(env->isolate());
517
28
    return v8::Just(errors->ToException(env).ToLocal(err));
518
  }
519
520
6
  SET_SELF_SIZE(DeriveBitsJob)
521
3
  void MemoryInfo(MemoryTracker* tracker) const override {
522
6
    tracker->TrackFieldWithSize("out", out_.size());
523
6
    CryptoJob<DeriveBitsTraits>::MemoryInfo(tracker);
524
  }
525
526
 private:
527
  ByteSource out_;
528
  bool success_ = false;
529
};
530
531
void ThrowCryptoError(Environment* env,
532
                      unsigned long err,  // NOLINT(runtime/int)
533
                      const char* message = nullptr);
534
535
#ifndef OPENSSL_NO_ENGINE
536
struct EnginePointer {
537
  ENGINE* engine = nullptr;
538
  bool finish_on_exit = false;
539
540
2488
  inline EnginePointer() = default;
541
542
13
  inline explicit EnginePointer(ENGINE* engine_, bool finish_on_exit_ = false)
543
13
    : engine(engine_),
544
13
      finish_on_exit(finish_on_exit_) {}
545
546
2
  inline EnginePointer(EnginePointer&& other) noexcept
547
2
      : engine(other.engine),
548
2
        finish_on_exit(other.finish_on_exit) {
549
2
    other.release();
550
2
  }
551
552
2494
  inline ~EnginePointer() { reset(); }
553
554
2
  inline EnginePointer& operator=(EnginePointer&& other) noexcept {
555
2
    if (this == &other) return *this;
556
2
    this->~EnginePointer();
557
2
    return *new (this) EnginePointer(std::move(other));
558
  }
559
560
35
  inline operator bool() const { return engine != nullptr; }
561
562
13
  inline ENGINE* get() { return engine; }
563
564
2496
  inline void reset(ENGINE* engine_ = nullptr, bool finish_on_exit_ = false) {
565
2496
    if (engine != nullptr) {
566
11
      if (finish_on_exit) {
567
        // This also does the equivalent of ENGINE_free.
568
        CHECK_EQ(ENGINE_finish(engine), 1);
569
      } else {
570
11
        CHECK_EQ(ENGINE_free(engine), 1);
571
      }
572
    }
573
2496
    engine = engine_;
574
2496
    finish_on_exit = finish_on_exit_;
575
2496
  }
576
577
2
  inline ENGINE* release() {
578
2
    ENGINE* ret = engine;
579
2
    engine = nullptr;
580
2
    finish_on_exit = false;
581
2
    return ret;
582
  }
583
};
584
585
EnginePointer LoadEngineById(const char* id, CryptoErrorStore* errors);
586
587
bool SetEngine(
588
    const char* id,
589
    uint32_t flags,
590
    CryptoErrorStore* errors = nullptr);
591
592
void SetEngine(const v8::FunctionCallbackInfo<v8::Value>& args);
593
#endif  // !OPENSSL_NO_ENGINE
594
595
void GetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
596
597
void SetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
598
599
void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
600
601
class CipherPushContext {
602
 public:
603
7
  inline explicit CipherPushContext(Environment* env) : env_(env) {}
604
605
581
  inline void push_back(const char* str) {
606
581
    list_.emplace_back(OneByteString(env_->isolate(), str));
607
581
  }
608
609
7
  inline v8::Local<v8::Array> ToJSArray() {
610
7
    return v8::Array::New(env_->isolate(), list_.data(), list_.size());
611
  }
612
613
 private:
614
  std::vector<v8::Local<v8::Value>> list_;
615
  Environment* env_;
616
};
617
618
#if OPENSSL_VERSION_MAJOR >= 3
619
template <class TypeName,
620
          TypeName* fetch_type(OSSL_LIB_CTX*, const char*, const char*),
621
          void free_type(TypeName*),
622
          const TypeName* getbyname(const char*),
623
          const char* getname(const TypeName*)>
624
761
void array_push_back(const TypeName* evp_ref,
625
                     const char* from,
626
                     const char* to,
627
                     void* arg) {
628
761
  if (!from)
629
    return;
630
631
761
  const TypeName* real_instance = getbyname(from);
632
761
  if (!real_instance)
633
    return;
634
635
761
  const char* real_name = getname(real_instance);
636
761
  if (!real_name)
637
    return;
638
639
  // EVP_*_fetch() does not support alias names, so we need to pass it the
640
  // real/original algorithm name.
641
  // We use EVP_*_fetch() as a filter here because it will only return an
642
  // instance if the algorithm is supported by the public OpenSSL APIs (some
643
  // algorithms are used internally by OpenSSL and are also passed to this
644
  // callback).
645
761
  TypeName* fetched = fetch_type(nullptr, real_name, nullptr);
646
761
  if (!fetched)
647
180
    return;
648
649
581
  free_type(fetched);
650
581
  static_cast<CipherPushContext*>(arg)->push_back(from);
651
}
652
#else
653
template <class TypeName>
654
void array_push_back(const TypeName* evp_ref,
655
                     const char* from,
656
                     const char* to,
657
                     void* arg) {
658
  if (!from)
659
    return;
660
  static_cast<CipherPushContext*>(arg)->push_back(from);
661
}
662
#endif
663
664
131504
inline bool IsAnyByteSource(v8::Local<v8::Value> arg) {
665
138588
  return arg->IsArrayBufferView() ||
666

145672
         arg->IsArrayBuffer() ||
667
135963
         arg->IsSharedArrayBuffer();
668
}
669
670
template <typename T>
671
class ArrayBufferOrViewContents {
672
 public:
673
  ArrayBufferOrViewContents() = default;
674
675
219481
  inline explicit ArrayBufferOrViewContents(v8::Local<v8::Value> buf) {
676
219481
    CHECK(IsAnyByteSource(buf));
677
219481
    if (buf->IsArrayBufferView()) {
678
217124
      auto view = buf.As<v8::ArrayBufferView>();
679
217124
      offset_ = view->ByteOffset();
680
217124
      length_ = view->ByteLength();
681
434248
      store_ = view->Buffer()->GetBackingStore();
682
2357
    } else if (buf->IsArrayBuffer()) {
683
2341
      auto ab = buf.As<v8::ArrayBuffer>();
684
2341
      offset_ = 0;
685
2341
      length_ = ab->ByteLength();
686
2341
      store_ = ab->GetBackingStore();
687
    } else {
688
16
      auto sab = buf.As<v8::SharedArrayBuffer>();
689
16
      offset_ = 0;
690
16
      length_ = sab->ByteLength();
691
16
      store_ = sab->GetBackingStore();
692
    }
693
219481
  }
694
695
14363
  inline const T* data() const {
696
    // Ideally, these would return nullptr if IsEmpty() or length_ is zero,
697
    // but some of the openssl API react badly if given a nullptr even when
698
    // length is zero, so we have to return something.
699
14363
    if (size() == 0)
700
131
      return &buf;
701
14232
    return reinterpret_cast<T*>(store_->Data()) + offset_;
702
  }
703
704
103222
  inline T* data() {
705
    // Ideally, these would return nullptr if IsEmpty() or length_ is zero,
706
    // but some of the openssl API react badly if given a nullptr even when
707
    // length is zero, so we have to return something.
708
103222
    if (size() == 0)
709
3
      return &buf;
710
103219
    return reinterpret_cast<T*>(store_->Data()) + offset_;
711
  }
712
713
676063
  inline size_t size() const { return length_; }
714
715
  // In most cases, input buffer sizes passed in to openssl need to
716
  // be limited to <= INT_MAX. This utility method helps us check.
717
214352
  inline bool CheckSizeInt32() { return size() <= INT_MAX; }
718
719
5015
  inline ByteSource ToByteSource() const {
720
5015
    return ByteSource::Foreign(data(), size());
721
  }
722
723
6958
  inline ByteSource ToCopy() const {
724
6958
    if (size() == 0) return ByteSource();
725
6356
    char* buf = MallocOpenSSL<char>(size());
726
6356
    CHECK_NOT_NULL(buf);
727
6356
    memcpy(buf, data(), size());
728
6356
    return ByteSource::Allocated(buf, size());
729
  }
730
731
95
  inline ByteSource ToNullTerminatedCopy() const {
732
95
    if (size() == 0) return ByteSource();
733
88
    char* buf = MallocOpenSSL<char>(size() + 1);
734
88
    CHECK_NOT_NULL(buf);
735
88
    buf[size()] = 0;
736
88
    memcpy(buf, data(), size());
737
88
    return ByteSource::Allocated(buf, size());
738
  }
739
740
  template <typename M>
741
104
  void CopyTo(M* dest, size_t len) const {
742
    static_assert(sizeof(M) == 1, "sizeof(M) must equal 1");
743
104
    len = std::min(len, size());
744

104
    if (len > 0 && data() != nullptr)
745
104
      memcpy(dest, data(), len);
746
104
  }
747
748
 private:
749
  T buf = 0;
750
  size_t offset_ = 0;
751
  size_t length_ = 0;
752
  std::shared_ptr<v8::BackingStore> store_;
753
};
754
755
template <typename T>
756
std::vector<T> CopyBuffer(const ArrayBufferOrViewContents<T>& buf) {
757
  std::vector<T> vec;
758
  vec->resize(buf.size());
759
  if (vec->size() > 0 && buf.data() != nullptr)
760
    memcpy(vec->data(), buf.data(), vec->size());
761
  return vec;
762
}
763
764
template <typename T>
765
std::vector<T> CopyBuffer(v8::Local<v8::Value> buf) {
766
  return CopyBuffer(ArrayBufferOrViewContents<T>(buf));
767
}
768
769
v8::MaybeLocal<v8::Value> EncodeBignum(
770
    Environment* env,
771
    const BIGNUM* bn,
772
    int size,
773
    v8::Local<v8::Value>* error);
774
775
v8::Maybe<bool> SetEncodedValue(
776
    Environment* env,
777
    v8::Local<v8::Object> target,
778
    v8::Local<v8::String> name,
779
    const BIGNUM* bn,
780
    int size = 0);
781
782
namespace Util {
783
void Initialize(Environment* env, v8::Local<v8::Object> target);
784
void RegisterExternalReferences(ExternalReferenceRegistry* registry);
785
}  // namespace Util
786
787
}  // namespace crypto
788
}  // namespace node
789
790
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
791
#endif  // SRC_CRYPTO_CRYPTO_UTIL_H_