GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_util.h Lines: 225 231 97.4 %
Date: 2022-01-06 04:14:11 Branches: 74 111 66.7 %

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

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

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

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

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

2564
    if (result.IsJust() && result.FromJust()) {
413
2558
      args.GetReturnValue().Set(
414
          v8::Array::New(env->isolate(), ret, arraysize(ret)));
415
    }
416
  }
417
418
182700
  static void Initialize(
419
      v8::FunctionCallback new_fn,
420
      Environment* env,
421
      v8::Local<v8::Object> target) {
422
182700
    v8::Local<v8::FunctionTemplate> job = env->NewFunctionTemplate(new_fn);
423
182700
    job->Inherit(AsyncWrap::GetConstructorTemplate(env));
424
365400
    job->InstanceTemplate()->SetInternalFieldCount(
425
        AsyncWrap::kInternalFieldCount);
426
182700
    env->SetProtoMethod(job, "run", Run);
427
182700
    env->SetConstructorFunction(target, CryptoJobTraits::JobName, job);
428
182700
  }
429
430
206136
  static void RegisterExternalReferences(v8::FunctionCallback new_fn,
431
                                         ExternalReferenceRegistry* registry) {
432
206136
    registry->Register(new_fn);
433
206136
    registry->Register(Run);
434
206136
  }
435
436
 private:
437
  const CryptoJobMode mode_;
438
  CryptoErrorStore errors_;
439
  AdditionalParams params_;
440
};
441
442
template <typename DeriveBitsTraits>
443
class DeriveBitsJob final : public CryptoJob<DeriveBitsTraits> {
444
 public:
445
  using AdditionalParams = typename DeriveBitsTraits::AdditionalParameters;
446
447
3397
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
448
3397
    Environment* env = Environment::GetCurrent(args);
449
450
3397
    CryptoJobMode mode = GetCryptoJobMode(args[0]);
451
452
3397
    AdditionalParams params;
453
6794
    if (DeriveBitsTraits::AdditionalConfig(mode, args, 1, &params)
454
            .IsNothing()) {
455
      // The DeriveBitsTraits::AdditionalConfig is responsible for
456
      // calling an appropriate THROW_CRYPTO_* variant reporting
457
      // whatever error caused initialization to fail.
458
71
      return;
459
    }
460
461
3326
    new DeriveBitsJob(env, args.This(), mode, std::move(params));
462
  }
463
464
73950
  static void Initialize(
465
      Environment* env,
466
      v8::Local<v8::Object> target) {
467
73950
    CryptoJob<DeriveBitsTraits>::Initialize(New, env, target);
468
73950
  }
469
470
83436
  static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
471
83436
    CryptoJob<DeriveBitsTraits>::RegisterExternalReferences(New, registry);
472
83436
  }
473
474
3326
  DeriveBitsJob(
475
      Environment* env,
476
      v8::Local<v8::Object> object,
477
      CryptoJobMode mode,
478
      AdditionalParams&& params)
479
      : CryptoJob<DeriveBitsTraits>(
480
            env,
481
            object,
482
            DeriveBitsTraits::Provider,
483
            mode,
484
3326
            std::move(params)) {}
485
486
3326
  void DoThreadPoolWork() override {
487
3326
    if (!DeriveBitsTraits::DeriveBits(
488
            AsyncWrap::env(),
489
3326
            *CryptoJob<DeriveBitsTraits>::params(), &out_)) {
490
14
      CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors();
491
14
      errors->Capture();
492
14
      if (errors->Empty())
493
14
        errors->Insert(NodeCryptoError::DERIVING_BITS_FAILED);
494
14
      return;
495
    }
496
3312
    success_ = true;
497
  }
498
499
3326
  v8::Maybe<bool> ToResult(
500
      v8::Local<v8::Value>* err,
501
      v8::Local<v8::Value>* result) override {
502
3326
    Environment* env = AsyncWrap::env();
503
3326
    CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors();
504
3326
    if (success_) {
505
3312
      CHECK(errors->Empty());
506
3312
      *err = v8::Undefined(env->isolate());
507
3312
      return DeriveBitsTraits::EncodeOutput(
508
          env,
509
3312
          *CryptoJob<DeriveBitsTraits>::params(),
510
          &out_,
511
3312
          result);
512
    }
513
514
14
    if (errors->Empty())
515
      errors->Capture();
516
14
    CHECK(!errors->Empty());
517
28
    *result = v8::Undefined(env->isolate());
518
28
    return v8::Just(errors->ToException(env).ToLocal(err));
519
  }
520
521
6
  SET_SELF_SIZE(DeriveBitsJob)
522
3
  void MemoryInfo(MemoryTracker* tracker) const override {
523
6
    tracker->TrackFieldWithSize("out", out_.size());
524
6
    CryptoJob<DeriveBitsTraits>::MemoryInfo(tracker);
525
  }
526
527
 private:
528
  ByteSource out_;
529
  bool success_ = false;
530
};
531
532
void ThrowCryptoError(Environment* env,
533
                      unsigned long err,  // NOLINT(runtime/int)
534
                      const char* message = nullptr);
535
536
#ifndef OPENSSL_NO_ENGINE
537
struct EnginePointer {
538
  ENGINE* engine = nullptr;
539
  bool finish_on_exit = false;
540
541
2362
  inline EnginePointer() = default;
542
543
13
  inline explicit EnginePointer(ENGINE* engine_, bool finish_on_exit_ = false)
544
13
    : engine(engine_),
545
13
      finish_on_exit(finish_on_exit_) {}
546
547
2
  inline EnginePointer(EnginePointer&& other) noexcept
548
2
      : engine(other.engine),
549
2
        finish_on_exit(other.finish_on_exit) {
550
2
    other.release();
551
2
  }
552
553
2368
  inline ~EnginePointer() { reset(); }
554
555
2
  inline EnginePointer& operator=(EnginePointer&& other) noexcept {
556
2
    if (this == &other) return *this;
557
2
    this->~EnginePointer();
558
2
    return *new (this) EnginePointer(std::move(other));
559
  }
560
561
35
  inline operator bool() const { return engine != nullptr; }
562
563
13
  inline ENGINE* get() { return engine; }
564
565
2370
  inline void reset(ENGINE* engine_ = nullptr, bool finish_on_exit_ = false) {
566
2370
    if (engine != nullptr) {
567
11
      if (finish_on_exit) {
568
        // This also does the equivalent of ENGINE_free.
569
        CHECK_EQ(ENGINE_finish(engine), 1);
570
      } else {
571
11
        CHECK_EQ(ENGINE_free(engine), 1);
572
      }
573
    }
574
2370
    engine = engine_;
575
2370
    finish_on_exit = finish_on_exit_;
576
2370
  }
577
578
2
  inline ENGINE* release() {
579
2
    ENGINE* ret = engine;
580
2
    engine = nullptr;
581
2
    finish_on_exit = false;
582
2
    return ret;
583
  }
584
};
585
586
EnginePointer LoadEngineById(const char* id, CryptoErrorStore* errors);
587
588
bool SetEngine(
589
    const char* id,
590
    uint32_t flags,
591
    CryptoErrorStore* errors = nullptr);
592
593
void SetEngine(const v8::FunctionCallbackInfo<v8::Value>& args);
594
#endif  // !OPENSSL_NO_ENGINE
595
596
void GetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
597
598
void SetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
599
600
void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
601
602
class CipherPushContext {
603
 public:
604
7
  inline explicit CipherPushContext(Environment* env) : env_(env) {}
605
606
761
  inline void push_back(const char* str) {
607
761
    list_.emplace_back(OneByteString(env_->isolate(), str));
608
761
  }
609
610
7
  inline v8::Local<v8::Array> ToJSArray() {
611
7
    return v8::Array::New(env_->isolate(), list_.data(), list_.size());
612
  }
613
614
 private:
615
  std::vector<v8::Local<v8::Value>> list_;
616
  Environment* env_;
617
};
618
619
template <class TypeName>
620
761
void array_push_back(const TypeName* md,
621
                     const char* from,
622
                     const char* to,
623
                     void* arg) {
624
761
  static_cast<CipherPushContext*>(arg)->push_back(from);
625
761
}
626
627
128961
inline bool IsAnyByteSource(v8::Local<v8::Value> arg) {
628
135515
  return arg->IsArrayBufferView() ||
629

142069
         arg->IsArrayBuffer() ||
630
133393
         arg->IsSharedArrayBuffer();
631
}
632
633
template <typename T>
634
class ArrayBufferOrViewContents {
635
 public:
636
  ArrayBufferOrViewContents() = default;
637
638
217411
  inline explicit ArrayBufferOrViewContents(v8::Local<v8::Value> buf) {
639
217411
    CHECK(IsAnyByteSource(buf));
640
217411
    if (buf->IsArrayBufferView()) {
641
215557
      auto view = buf.As<v8::ArrayBufferView>();
642
215557
      offset_ = view->ByteOffset();
643
215557
      length_ = view->ByteLength();
644
431114
      store_ = view->Buffer()->GetBackingStore();
645
1854
    } else if (buf->IsArrayBuffer()) {
646
1838
      auto ab = buf.As<v8::ArrayBuffer>();
647
1838
      offset_ = 0;
648
1838
      length_ = ab->ByteLength();
649
1838
      store_ = ab->GetBackingStore();
650
    } else {
651
16
      auto sab = buf.As<v8::SharedArrayBuffer>();
652
16
      offset_ = 0;
653
16
      length_ = sab->ByteLength();
654
16
      store_ = sab->GetBackingStore();
655
    }
656
217411
  }
657
658
13038
  inline const T* data() const {
659
    // Ideally, these would return nullptr if IsEmpty() or length_ is zero,
660
    // but some of the openssl API react badly if given a nullptr even when
661
    // length is zero, so we have to return something.
662
13038
    if (size() == 0)
663
99
      return &buf;
664
12939
    return reinterpret_cast<T*>(store_->Data()) + offset_;
665
  }
666
667
102954
  inline T* data() {
668
    // Ideally, these would return nullptr if IsEmpty() or length_ is zero,
669
    // but some of the openssl API react badly if given a nullptr even when
670
    // length is zero, so we have to return something.
671
102954
    if (size() == 0)
672
3
      return &buf;
673
102951
    return reinterpret_cast<T*>(store_->Data()) + offset_;
674
  }
675
676
669369
  inline size_t size() const { return length_; }
677
678
  // In most cases, input buffer sizes passed in to openssl need to
679
  // be limited to <= INT_MAX. This utility method helps us check.
680
213204
  inline bool CheckSizeInt32() { return size() <= INT_MAX; }
681
682
4576
  inline ByteSource ToByteSource() const {
683
4576
    return ByteSource::Foreign(data(), size());
684
  }
685
686
6943
  inline ByteSource ToCopy() const {
687
6943
    if (size() == 0) return ByteSource();
688
6342
    char* buf = MallocOpenSSL<char>(size());
689
6342
    CHECK_NOT_NULL(buf);
690
6342
    memcpy(buf, data(), size());
691
6342
    return ByteSource::Allocated(buf, size());
692
  }
693
694
88
  inline ByteSource ToNullTerminatedCopy() const {
695
88
    if (size() == 0) return ByteSource();
696
88
    char* buf = MallocOpenSSL<char>(size() + 1);
697
88
    CHECK_NOT_NULL(buf);
698
88
    buf[size()] = 0;
699
88
    memcpy(buf, data(), size());
700
88
    return ByteSource::Allocated(buf, size());
701
  }
702
703
  template <typename M>
704
85
  void CopyTo(M* dest, size_t len) const {
705
    static_assert(sizeof(M) == 1, "sizeof(M) must equal 1");
706
85
    len = std::min(len, size());
707

85
    if (len > 0 && data() != nullptr)
708
85
      memcpy(dest, data(), len);
709
85
  }
710
711
 private:
712
  T buf = 0;
713
  size_t offset_ = 0;
714
  size_t length_ = 0;
715
  std::shared_ptr<v8::BackingStore> store_;
716
};
717
718
template <typename T>
719
std::vector<T> CopyBuffer(const ArrayBufferOrViewContents<T>& buf) {
720
  std::vector<T> vec;
721
  vec->resize(buf.size());
722
  if (vec->size() > 0 && buf.data() != nullptr)
723
    memcpy(vec->data(), buf.data(), vec->size());
724
  return vec;
725
}
726
727
template <typename T>
728
std::vector<T> CopyBuffer(v8::Local<v8::Value> buf) {
729
  return CopyBuffer(ArrayBufferOrViewContents<T>(buf));
730
}
731
732
v8::MaybeLocal<v8::Value> EncodeBignum(
733
    Environment* env,
734
    const BIGNUM* bn,
735
    int size,
736
    v8::Local<v8::Value>* error);
737
738
v8::Maybe<bool> SetEncodedValue(
739
    Environment* env,
740
    v8::Local<v8::Object> target,
741
    v8::Local<v8::String> name,
742
    const BIGNUM* bn,
743
    int size = 0);
744
745
namespace Util {
746
void Initialize(Environment* env, v8::Local<v8::Object> target);
747
void RegisterExternalReferences(ExternalReferenceRegistry* registry);
748
}  // namespace Util
749
750
}  // namespace crypto
751
}  // namespace node
752
753
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
754
#endif  // SRC_CRYPTO_CRYPTO_UTIL_H_