GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/crypto/crypto_util.h Lines: 210 230 91.3 %
Date: 2021-06-02 04:11:51 Branches: 141 256 55.1 %

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_internals.h"
11
#include "util.h"
12
#include "v8.h"
13
#include "string_bytes.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
void InitCryptoOnce();
90
91
void InitCrypto(v8::Local<v8::Object> target);
92
93
extern void UseExtraCaCerts(const std::string& file);
94
95
// Forcibly clear OpenSSL's error stack on return. This stops stale errors
96
// from popping up later in the lifecycle of crypto operations where they
97
// would cause spurious failures. It's a rather blunt method, though.
98
// ERR_clear_error() isn't necessarily cheap either.
99
struct ClearErrorOnReturn {
100
10300
  ~ClearErrorOnReturn() { ERR_clear_error(); }
101
};
102
103
// Pop errors from OpenSSL's error stack that were added
104
// between when this was constructed and destructed.
105
struct MarkPopErrorOnReturn {
106
19792
  MarkPopErrorOnReturn() { ERR_set_mark(); }
107
19791
  ~MarkPopErrorOnReturn() { ERR_pop_to_mark(); }
108
};
109
110
// Ensure that OpenSSL has enough entropy (at least 256 bits) for its PRNG.
111
// The entropy pool starts out empty and needs to fill up before the PRNG
112
// can be used securely.  Once the pool is filled, it never dries up again;
113
// its contents is stirred and reused when necessary.
114
//
115
// OpenSSL normally fills the pool automatically but not when someone starts
116
// generating random numbers before the pool is full: in that case OpenSSL
117
// keeps lowering the entropy estimate to thwart attackers trying to guess
118
// the initial state of the PRNG.
119
//
120
// When that happens, we will have to wait until enough entropy is available.
121
// That should normally never take longer than a few milliseconds.
122
//
123
// OpenSSL draws from /dev/random and /dev/urandom.  While /dev/random may
124
// block pending "true" randomness, /dev/urandom is a CSPRNG that doesn't
125
// block under normal circumstances.
126
//
127
// The only time when /dev/urandom may conceivably block is right after boot,
128
// when the whole system is still low on entropy.  That's not something we can
129
// do anything about.
130
void CheckEntropy();
131
132
// Generate length bytes of random data. If this returns false, the data
133
// may not be truly random but it's still generally good enough.
134
bool EntropySource(unsigned char* buffer, size_t length);
135
136
int PasswordCallback(char* buf, int size, int rwflag, void* u);
137
138
int NoPasswordCallback(char* buf, int size, int rwflag, void* u);
139
140
// Decode is used by the various stream-based crypto utilities to decode
141
// string input.
142
template <typename T>
143
3917
void Decode(const v8::FunctionCallbackInfo<v8::Value>& args,
144
            void (*callback)(T*, const v8::FunctionCallbackInfo<v8::Value>&,
145
                             const char*, size_t)) {
146
  T* ctx;
147

3917
  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
148
149

11751
  if (args[0]->IsString()) {
150
5202
    StringBytes::InlineDecoder decoder;
151
2601
    Environment* env = Environment::GetCurrent(args);
152
2601
    enum encoding enc = ParseEncoding(env->isolate(), args[1], UTF8);
153

7803
    if (decoder.Decode(env, args[0].As<v8::String>(), enc).IsNothing())
154
      return;
155

2601
    callback(ctx, args, decoder.out(), decoder.size());
156
  } else {
157
1316
    ArrayBufferViewContents<char> buf(args[0]);
158
1316
    callback(ctx, args, buf.data(), buf.length());
159
  }
160
}
161
162
#define NODE_CRYPTO_ERROR_CODES_MAP(V)                                        \
163
    V(CIPHER_JOB_FAILED, "Cipher job failed")                                 \
164
    V(DERIVING_BITS_FAILED, "Deriving bits failed")                           \
165
    V(ENGINE_NOT_FOUND, "Engine \"%s\" was not found")                        \
166
    V(INVALID_KEY_TYPE, "Invalid key type")                                   \
167
    V(KEY_GENERATION_JOB_FAILED, "Key generation job failed")                 \
168
    V(OK, "Ok")                                                               \
169
170
enum class NodeCryptoError {
171
#define V(CODE, DESCRIPTION) CODE,
172
  NODE_CRYPTO_ERROR_CODES_MAP(V)
173
#undef V
174
};
175
176
// Utility struct used to harvest error information from openssl's error stack
177
6302
struct CryptoErrorStore final : public MemoryRetainer {
178
 public:
179
  void Capture();
180
181
  bool Empty() const;
182
183
  template <typename... Args>
184
  void Insert(const NodeCryptoError error, Args&&... args);
185
186
  v8::MaybeLocal<v8::Value> ToException(
187
      Environment* env,
188
      v8::Local<v8::String> exception_string = v8::Local<v8::String>()) const;
189
190
3
  SET_NO_MEMORY_INFO()
191
3
  SET_MEMORY_INFO_NAME(CryptoErrorStore)
192
3
  SET_SELF_SIZE(CryptoErrorStore)
193
194
 private:
195
  std::vector<std::string> errors_;
196
};
197
198
template <typename... Args>
199
void CryptoErrorStore::Insert(const NodeCryptoError error, Args&&... args) {
200
  const char* error_string = nullptr;
201
  switch (error) {
202
#define V(CODE, DESCRIPTION) \
203
    case NodeCryptoError::CODE: error_string = DESCRIPTION; break;
204
    NODE_CRYPTO_ERROR_CODES_MAP(V)
205
#undef V
206
  }
207
  errors_.emplace_back(SPrintF(error_string,
208
                               std::forward<Args>(args)...));
209
}
210
211
template <typename T>
212
9722
T* MallocOpenSSL(size_t count) {
213
9722
  void* mem = OPENSSL_malloc(MultiplyWithOverflowCheck(count, sizeof(T)));
214


9722
  CHECK_IMPLIES(mem == nullptr, count == 0);
215
9722
  return static_cast<T*>(mem);
216
}
217
218
template <typename T>
219
525
T* ReallocOpenSSL(T* buf, size_t count) {
220
525
  void* mem = OPENSSL_realloc(buf, MultiplyWithOverflowCheck(count, sizeof(T)));
221

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

3036
    if (mode == kCryptoJobSync) MakeWeak();
332
3036
  }
333
334
  bool IsNotIndicativeOfMemoryLeakAtExit() const override {
335
    // CryptoJobs run a work in the libuv thread pool and may still
336
    // exist when the event loop empties and starts to exit.
337
    return true;
338
  }
339
340
2082
  void AfterThreadPoolWork(int status) override {
341
2082
    Environment* env = AsyncWrap::env();
342

2082
    CHECK_EQ(mode_, kCryptoJobAsync);
343



2082
    CHECK(status == 0 || status == UV_ECANCELED);
344
4164
    std::unique_ptr<CryptoJob> ptr(this);
345
    // If the job was canceled do not execute the callback.
346
    // TODO(@jasnell): We should likely revisit skipping the
347
    // callback on cancel as that could leave the JS in a pending
348
    // state (e.g. unresolved promises...)
349

2082
    if (status == UV_ECANCELED) return;
350

4164
    v8::HandleScope handle_scope(env->isolate());
351

4164
    v8::Context::Scope context_scope(env->context());
352
353
    // TODO(tniessen): Remove the exception handling logic here as soon as we
354
    // can verify that no code path in ToResult will ever throw an exception.
355
    v8::Local<v8::Value> exception;
356

6246
    v8::Local<v8::Value> args[2];
357
    {
358
4164
      node::errors::TryCatchScope try_catch(env);
359
2082
      v8::Maybe<bool> ret = ptr->ToResult(&args[0], &args[1]);
360

2082
      if (!ret.IsJust()) {
361

2
        CHECK(try_catch.HasCaught());
362
2
        exception = try_catch.Exception();
363

2080
      } else if (!ret.FromJust()) {
364
        return;
365
      }
366
    }
367
368

2082
    if (exception.IsEmpty()) {
369
2080
      ptr->MakeCallback(env->ondone_string(), arraysize(args), args);
370
    } else {
371
2
      ptr->MakeCallback(env->ondone_string(), 1, &exception);
372
    }
373
  }
374
375
  virtual v8::Maybe<bool> ToResult(
376
      v8::Local<v8::Value>* err,
377
      v8::Local<v8::Value>* result) = 0;
378
379
3029
  CryptoJobMode mode() const { return mode_; }
380
381
3046
  CryptoErrorStore* errors() { return &errors_; }
382
383
5378
  AdditionalParams* params() { return &params_; }
384
385
3
  std::string MemoryInfoName() const override {
386
3
    return CryptoJobTraits::JobName;
387
  }
388
389
3
  void MemoryInfo(MemoryTracker* tracker) const override {
390
3
    tracker->TrackField("params", params_);
391
3
    tracker->TrackField("errors", errors_);
392
3
  }
393
394
3029
  static void Run(const v8::FunctionCallbackInfo<v8::Value>& args) {
395
3029
    Environment* env = Environment::GetCurrent(args);
396
397
    CryptoJob<CryptoJobTraits>* job;
398

5112
    ASSIGN_OR_RETURN_UNWRAP(&job, args.Holder());
399

3029
    if (job->mode() == kCryptoJobAsync)
400
2083
      return job->ScheduleWork();
401
402

2838
    v8::Local<v8::Value> ret[2];
403
946
    env->PrintSyncTrace();
404
946
    job->DoThreadPoolWork();
405
946
    v8::Maybe<bool> result = job->ToResult(&ret[0], &ret[1]);
406




1890
    if (result.IsJust() && result.FromJust()) {
407
2832
      args.GetReturnValue().Set(
408
          v8::Array::New(env->isolate(), ret, arraysize(ret)));
409
    }
410
  }
411
412
95795
  static void Initialize(
413
      v8::FunctionCallback new_fn,
414
      Environment* env,
415
      v8::Local<v8::Object> target) {
416
95795
    v8::Local<v8::FunctionTemplate> job = env->NewFunctionTemplate(new_fn);
417
191590
    job->Inherit(AsyncWrap::GetConstructorTemplate(env));
418
191590
    job->InstanceTemplate()->SetInternalFieldCount(
419
        AsyncWrap::kInternalFieldCount);
420
95795
    env->SetProtoMethod(job, "run", Run);
421
95795
    env->SetConstructorFunction(target, CryptoJobTraits::JobName, job);
422
95795
  }
423
424
 private:
425
  const CryptoJobMode mode_;
426
  CryptoErrorStore errors_;
427
  AdditionalParams params_;
428
};
429
430
template <typename DeriveBitsTraits>
431
4230
class DeriveBitsJob final : public CryptoJob<DeriveBitsTraits> {
432
 public:
433
  using AdditionalParams = typename DeriveBitsTraits::AdditionalParameters;
434
435
2152
  static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
436
2152
    Environment* env = Environment::GetCurrent(args);
437
438
2152
    CryptoJobMode mode = GetCryptoJobMode(args[0]);
439
440
4268
    AdditionalParams params;
441

4304
    if (DeriveBitsTraits::AdditionalConfig(mode, args, 1, &params)
442
            .IsNothing()) {
443
      // The DeriveBitsTraits::AdditionalConfig is responsible for
444
      // calling an appropriate THROW_CRYPTO_* variant reporting
445
      // whatever error caused initialization to fail.
446
36
      return;
447
    }
448
449

2116
    new DeriveBitsJob(env, args.This(), mode, std::move(params));
450
  }
451
452
45815
  static void Initialize(
453
      Environment* env,
454
      v8::Local<v8::Object> target) {
455
45815
    CryptoJob<DeriveBitsTraits>::Initialize(New, env, target);
456
45815
  }
457
458
2116
  DeriveBitsJob(
459
      Environment* env,
460
      v8::Local<v8::Object> object,
461
      CryptoJobMode mode,
462
      AdditionalParams&& params)
463
      : CryptoJob<DeriveBitsTraits>(
464
            env,
465
            object,
466
            DeriveBitsTraits::Provider,
467
            mode,
468
2116
            std::move(params)) {}
469
470
2116
  void DoThreadPoolWork() override {
471

4232
    if (!DeriveBitsTraits::DeriveBits(
472
            AsyncWrap::env(),
473
2116
            *CryptoJob<DeriveBitsTraits>::params(), &out_)) {
474
      CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors();
475
      errors->Capture();
476
      if (errors->Empty())
477
        errors->Insert(NodeCryptoError::DERIVING_BITS_FAILED);
478
      return;
479
    }
480
2116
    success_ = true;
481
  }
482
483
2116
  v8::Maybe<bool> ToResult(
484
      v8::Local<v8::Value>* err,
485
      v8::Local<v8::Value>* result) override {
486
2116
    Environment* env = AsyncWrap::env();
487
2116
    CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors();
488

2116
    if (success_) {
489

2116
      CHECK(errors->Empty());
490
4232
      *err = v8::Undefined(env->isolate());
491
2116
      return DeriveBitsTraits::EncodeOutput(
492
          env,
493
2116
          *CryptoJob<DeriveBitsTraits>::params(),
494
          &out_,
495
2116
          result);
496
    }
497
498
    if (errors->Empty())
499
      errors->Capture();
500
    CHECK(!errors->Empty());
501
    *result = v8::Undefined(env->isolate());
502
    return v8::Just(errors->ToException(env).ToLocal(err));
503
  }
504
505
3
  SET_SELF_SIZE(DeriveBitsJob)
506
3
  void MemoryInfo(MemoryTracker* tracker) const override {
507
3
    tracker->TrackFieldWithSize("out", out_.size());
508
3
    CryptoJob<DeriveBitsTraits>::MemoryInfo(tracker);
509
3
  }
510
511
 private:
512
  ByteSource out_;
513
  bool success_ = false;
514
};
515
516
void ThrowCryptoError(Environment* env,
517
                      unsigned long err,  // NOLINT(runtime/int)
518
                      const char* message = nullptr);
519
520
#ifndef OPENSSL_NO_ENGINE
521
struct EnginePointer {
522
  ENGINE* engine = nullptr;
523
  bool finish_on_exit = false;
524
525
2363
  inline EnginePointer() = default;
526
527
4
  inline explicit EnginePointer(ENGINE* engine_, bool finish_on_exit_ = false)
528
4
    : engine(engine_),
529
4
      finish_on_exit(finish_on_exit_) {}
530
531
2
  inline EnginePointer(EnginePointer&& other) noexcept
532
2
      : engine(other.engine),
533
2
        finish_on_exit(other.finish_on_exit) {
534
2
    other.release();
535
2
  }
536
537
2345
  inline ~EnginePointer() { reset(); }
538
539
2
  inline EnginePointer& operator=(EnginePointer&& other) noexcept {
540
2
    if (this == &other) return *this;
541
2
    this->~EnginePointer();
542
2
    return *new (this) EnginePointer(std::move(other));
543
  }
544
545
8
  inline operator bool() const { return engine != nullptr; }
546
547
4
  inline ENGINE* get() { return engine; }
548
549
2347
  inline void reset(ENGINE* engine_ = nullptr, bool finish_on_exit_ = false) {
550
2347
    if (engine != nullptr) {
551
2
      if (finish_on_exit)
552
        ENGINE_finish(engine);
553
2
      ENGINE_free(engine);
554
    }
555
2347
    engine = engine_;
556
2347
    finish_on_exit = finish_on_exit_;
557
2347
  }
558
559
2
  inline ENGINE* release() {
560
2
    ENGINE* ret = engine;
561
2
    engine = nullptr;
562
2
    finish_on_exit = false;
563
2
    return ret;
564
  }
565
};
566
567
EnginePointer LoadEngineById(const char* id, CryptoErrorStore* errors);
568
569
bool SetEngine(
570
    const char* id,
571
    uint32_t flags,
572
    CryptoErrorStore* errors = nullptr);
573
574
void SetEngine(const v8::FunctionCallbackInfo<v8::Value>& args);
575
#endif  // !OPENSSL_NO_ENGINE
576
577
void GetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
578
579
void SetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
580
581
void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
582
583
10
class CipherPushContext {
584
 public:
585
10
  inline explicit CipherPushContext(Environment* env) : env_(env) {}
586
587
938
  inline void push_back(const char* str) {
588
938
    list_.emplace_back(OneByteString(env_->isolate(), str));
589
938
  }
590
591
10
  inline v8::Local<v8::Array> ToJSArray() {
592
10
    return v8::Array::New(env_->isolate(), list_.data(), list_.size());
593
  }
594
595
 private:
596
  std::vector<v8::Local<v8::Value>> list_;
597
  Environment* env_;
598
};
599
600
template <class TypeName>
601
938
void array_push_back(const TypeName* md,
602
                     const char* from,
603
                     const char* to,
604
                     void* arg) {
605
938
  static_cast<CipherPushContext*>(arg)->push_back(from);
606
938
}
607
608
121132
inline bool IsAnyByteSource(v8::Local<v8::Value> arg) {
609
125008
  return arg->IsArrayBufferView() ||
610

127699
         arg->IsArrayBuffer() ||
611
123823
         arg->IsSharedArrayBuffer();
612
}
613
614
template <typename T>
615
114089
class ArrayBufferOrViewContents {
616
 public:
617
  ArrayBufferOrViewContents() = default;
618
619
111565
  inline explicit ArrayBufferOrViewContents(v8::Local<v8::Value> buf) {
620

111565
    CHECK(IsAnyByteSource(buf));
621

111565
    if (buf->IsArrayBufferView()) {
622
110582
      auto view = buf.As<v8::ArrayBufferView>();
623
110582
      offset_ = view->ByteOffset();
624
110582
      length_ = view->ByteLength();
625
221164
      store_ = view->Buffer()->GetBackingStore();
626

983
    } else if (buf->IsArrayBuffer()) {
627
965
      auto ab = buf.As<v8::ArrayBuffer>();
628
965
      offset_ = 0;
629
965
      length_ = ab->ByteLength();
630
965
      store_ = ab->GetBackingStore();
631
    } else {
632
18
      auto sab = buf.As<v8::SharedArrayBuffer>();
633
18
      offset_ = 0;
634
18
      length_ = sab->ByteLength();
635
18
      store_ = sab->GetBackingStore();
636
    }
637
111565
  }
638
639
8667
  inline const T* data() const {
640
    // Ideally, these would return nullptr if IsEmpty() or length_ is zero,
641
    // but some of the openssl API react badly if given a nullptr even when
642
    // length is zero, so we have to return something.
643

8667
    if (size() == 0)
644
96
      return &buf;
645
8571
    return reinterpret_cast<T*>(store_->Data()) + offset_;
646
  }
647
648
102265
  inline T* data() {
649
    // Ideally, these would return nullptr if IsEmpty() or length_ is zero,
650
    // but some of the openssl API react badly if given a nullptr even when
651
    // length is zero, so we have to return something.
652

102265
    if (size() == 0)
653
3
      return &buf;
654
102262
    return reinterpret_cast<T*>(store_->Data()) + offset_;
655
  }
656
657
343146
  inline size_t size() const { return length_; }
658
659
  // In most cases, input buffer sizes passed in to openssl need to
660
  // be limited to <= INT_MAX. This utility method helps us check.
661
108642
  inline bool CheckSizeInt32() { return size() <= INT_MAX; }
662
663
4020
  inline ByteSource ToByteSource() const {
664
4020
    return ByteSource::Foreign(data(), size());
665
  }
666
667
3794
  inline ByteSource ToCopy() const {
668
3794
    if (size() == 0) return ByteSource();
669
3242
    char* buf = MallocOpenSSL<char>(size());
670
3242
    CHECK_NOT_NULL(buf);
671
3242
    memcpy(buf, data(), size());
672
3242
    return ByteSource::Allocated(buf, size());
673
  }
674
675
96
  inline ByteSource ToNullTerminatedCopy() const {
676
96
    if (size() == 0) return ByteSource();
677
90
    char* buf = MallocOpenSSL<char>(size() + 1);
678
90
    CHECK_NOT_NULL(buf);
679
90
    buf[size()] = 0;
680
90
    memcpy(buf, data(), size());
681
90
    return ByteSource::Allocated(buf, size());
682
  }
683
684
  template <typename M>
685
85
  void CopyTo(M* dest, size_t len) const {
686
    static_assert(sizeof(M) == 1, "sizeof(M) must equal 1");
687
85
    len = std::min(len, size());
688

85
    if (len > 0 && data() != nullptr)
689
85
      memcpy(dest, data(), len);
690
85
  }
691
692
 private:
693
  T buf = 0;
694
  size_t offset_ = 0;
695
  size_t length_ = 0;
696
  std::shared_ptr<v8::BackingStore> store_;
697
};
698
699
template <typename T>
700
std::vector<T> CopyBuffer(const ArrayBufferOrViewContents<T>& buf) {
701
  std::vector<T> vec;
702
  vec->resize(buf.size());
703
  if (vec->size() > 0 && buf.data() != nullptr)
704
    memcpy(vec->data(), buf.data(), vec->size());
705
  return vec;
706
}
707
708
template <typename T>
709
std::vector<T> CopyBuffer(v8::Local<v8::Value> buf) {
710
  return CopyBuffer(ArrayBufferOrViewContents<T>(buf));
711
}
712
713
v8::MaybeLocal<v8::Value> EncodeBignum(
714
    Environment* env,
715
    const BIGNUM* bn,
716
    int size,
717
    v8::Local<v8::Value>* error);
718
719
v8::Maybe<bool> SetEncodedValue(
720
    Environment* env,
721
    v8::Local<v8::Object> target,
722
    v8::Local<v8::String> name,
723
    const BIGNUM* bn,
724
    int size = 0);
725
726
namespace Util {
727
void Initialize(Environment* env, v8::Local<v8::Object> target);
728
}  // namespace Util
729
730
}  // namespace crypto
731
}  // namespace node
732
733
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
734
#endif  // SRC_CRYPTO_CRYPTO_UTIL_H_