GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_util.h Lines: 243 252 96.4 %
Date: 2022-08-16 04:20:39 Branches: 80 115 69.6 %

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 <climits>
33
#include <cstdio>
34
#include <memory>
35
#include <optional>
36
#include <string>
37
#include <vector>
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
11209
  ~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
26052
  MarkPopErrorOnReturn() { ERR_set_mark(); }
111
26051
  ~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
3735
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
3735
  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
152
153
7470
  if (args[0]->IsString()) {
154
1847
    StringBytes::InlineDecoder decoder;
155
1847
    Environment* env = Environment::GetCurrent(args);
156
1847
    enum encoding enc = ParseEncoding(env->isolate(), args[1], UTF8);
157
5541
    if (decoder.Decode(env, args[0].As<v8::String>(), enc).IsNothing())
158
      return;
159
1847
    callback(ctx, args, decoder.out(), decoder.size());
160
  } else {
161
1888
    ArrayBufferViewContents<char> buf(args[0]);
162
1888
    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
24840
T* MallocOpenSSL(size_t count) {
217
24840
  void* mem = OPENSSL_malloc(MultiplyWithOverflowCheck(count, sizeof(T)));
218

24840
  CHECK_IMPLIES(mem == nullptr, count == 0);
219
24840
  return static_cast<T*>(mem);
220
}
221
222
// A helper class representing a read-only byte array. When deallocated, its
223
// contents are zeroed.
224
class ByteSource {
225
 public:
226
  class Builder {
227
   public:
228
    // Allocates memory using OpenSSL's memory allocator.
229
23643
    explicit Builder(size_t size)
230
23643
        : data_(MallocOpenSSL<char>(size)), size_(size) {}
231
232
    Builder(Builder&& other) = delete;
233
    Builder& operator=(Builder&& other) = delete;
234
    Builder(const Builder&) = delete;
235
    Builder& operator=(const Builder&) = delete;
236
237
23643
    ~Builder() { OPENSSL_clear_free(data_, size_); }
238
239
    // Returns the underlying non-const pointer.
240
    template <typename T>
241
51184
    T* data() {
242
51184
      return reinterpret_cast<T*>(data_);
243
    }
244
245
    // Returns the (allocated) size in bytes.
246
13
    size_t size() const { return size_; }
247
248
    // Finalizes the Builder and returns a read-only view that is optionally
249
    // truncated.
250
23555
    ByteSource release(std::optional<size_t> resize = std::nullopt) && {
251
23555
      if (resize) {
252
4683
        CHECK_LE(*resize, size_);
253
4683
        if (*resize == 0) {
254
1
          OPENSSL_clear_free(data_, size_);
255
1
          data_ = nullptr;
256
        }
257
4683
        size_ = *resize;
258
      }
259
23555
      ByteSource out = ByteSource::Allocated(data_, size_);
260
23555
      data_ = nullptr;
261
23555
      size_ = 0;
262
23555
      return out;
263
    }
264
265
   private:
266
    void* data_;
267
    size_t size_;
268
  };
269
270
33678
  ByteSource() = default;
271
  ByteSource(ByteSource&& other) noexcept;
272
  ~ByteSource();
273
274
  ByteSource& operator=(ByteSource&& other) noexcept;
275
276
  ByteSource(const ByteSource&) = delete;
277
  ByteSource& operator=(const ByteSource&) = delete;
278
279
  template <typename T = void>
280
61176
  const T* data() const {
281
61176
    return reinterpret_cast<const T*>(data_);
282
  }
283
284
37797
  size_t size() const { return size_; }
285
286
2714
  operator bool() const { return data_ != nullptr; }
287
288
2841
  BignumPointer ToBN() const {
289
2841
    return BignumPointer(BN_bin2bn(data<unsigned char>(), size(), nullptr));
290
  }
291
292
  // Creates a v8::BackingStore that takes over responsibility for
293
  // any allocated data. The ByteSource will be reset with size = 0
294
  // after being called.
295
  std::unique_ptr<v8::BackingStore> ReleaseToBackingStore();
296
297
  v8::Local<v8::ArrayBuffer> ToArrayBuffer(Environment* env);
298
299
  v8::MaybeLocal<v8::Uint8Array> ToBuffer(Environment* env);
300
301
  static ByteSource Allocated(void* data, size_t size);
302
  static ByteSource Foreign(const void* data, size_t size);
303
304
  static ByteSource FromEncodedString(Environment* env,
305
                                      v8::Local<v8::String> value,
306
                                      enum encoding enc = BASE64);
307
308
  static ByteSource FromStringOrBuffer(Environment* env,
309
                                       v8::Local<v8::Value> value);
310
311
  static ByteSource FromString(Environment* env,
312
                               v8::Local<v8::String> str,
313
                               bool ntc = false);
314
315
  static ByteSource FromBuffer(v8::Local<v8::Value> buffer,
316
                               bool ntc = false);
317
318
  static ByteSource FromBIO(const BIOPointer& bio);
319
320
  static ByteSource NullTerminatedCopy(Environment* env,
321
                                       v8::Local<v8::Value> value);
322
323
  static ByteSource FromSymmetricKeyObjectHandle(v8::Local<v8::Value> handle);
324
325
  static ByteSource FromSecretKeyBytes(
326
      Environment* env, v8::Local<v8::Value> value);
327
328
 private:
329
  const void* data_ = nullptr;
330
  void* allocated_data_ = nullptr;
331
  size_t size_ = 0;
332
333
31346
  ByteSource(const void* data, void* allocated_data, size_t size)
334
31346
      : data_(data), allocated_data_(allocated_data), size_(size) {}
335
};
336
337
enum CryptoJobMode {
338
  kCryptoJobAsync,
339
  kCryptoJobSync
340
};
341
342
CryptoJobMode GetCryptoJobMode(v8::Local<v8::Value> args);
343
344
template <typename CryptoJobTraits>
345
class CryptoJob : public AsyncWrap, public ThreadPoolWork {
346
 public:
347
  using AdditionalParams = typename CryptoJobTraits::AdditionalParameters;
348
349
16042
  explicit CryptoJob(
350
      Environment* env,
351
      v8::Local<v8::Object> object,
352
      AsyncWrap::ProviderType type,
353
      CryptoJobMode mode,
354
      AdditionalParams&& params)
355
      : AsyncWrap(env, object, type),
356
        ThreadPoolWork(env),
357
        mode_(mode),
358
16042
        params_(std::move(params)) {
359
    // If the CryptoJob is async, then the instance will be
360
    // cleaned up when AfterThreadPoolWork is called.
361
16042
    if (mode == kCryptoJobSync) MakeWeak();
362
16042
  }
363
364
  bool IsNotIndicativeOfMemoryLeakAtExit() const override {
365
    // CryptoJobs run a work in the libuv thread pool and may still
366
    // exist when the event loop empties and starts to exit.
367
    return true;
368
  }
369
370
14211
  void AfterThreadPoolWork(int status) override {
371
14211
    Environment* env = AsyncWrap::env();
372
14211
    CHECK_EQ(mode_, kCryptoJobAsync);
373

14211
    CHECK(status == 0 || status == UV_ECANCELED);
374
14211
    std::unique_ptr<CryptoJob> ptr(this);
375
    // If the job was canceled do not execute the callback.
376
    // TODO(@jasnell): We should likely revisit skipping the
377
    // callback on cancel as that could leave the JS in a pending
378
    // state (e.g. unresolved promises...)
379
14211
    if (status == UV_ECANCELED) return;
380
14211
    v8::HandleScope handle_scope(env->isolate());
381
28422
    v8::Context::Scope context_scope(env->context());
382
383
    // TODO(tniessen): Remove the exception handling logic here as soon as we
384
    // can verify that no code path in ToResult will ever throw an exception.
385
    v8::Local<v8::Value> exception;
386
42633
    v8::Local<v8::Value> args[2];
387
    {
388
14211
      node::errors::TryCatchScope try_catch(env);
389
14211
      v8::Maybe<bool> ret = ptr->ToResult(&args[0], &args[1]);
390
14211
      if (!ret.IsJust()) {
391
4
        CHECK(try_catch.HasCaught());
392
4
        exception = try_catch.Exception();
393
14207
      } else if (!ret.FromJust()) {
394
        return;
395
      }
396
    }
397
398
14211
    if (exception.IsEmpty()) {
399
14207
      ptr->MakeCallback(env->ondone_string(), arraysize(args), args);
400
    } else {
401
4
      ptr->MakeCallback(env->ondone_string(), 1, &exception);
402
    }
403
  }
404
405
  virtual v8::Maybe<bool> ToResult(
406
      v8::Local<v8::Value>* err,
407
      v8::Local<v8::Value>* result) = 0;
408
409
16036
  CryptoJobMode mode() const { return mode_; }
410
411
16299
  CryptoErrorStore* errors() { return &errors_; }
412
413
29275
  AdditionalParams* params() { return &params_; }
414
415
6
  std::string MemoryInfoName() const override {
416
6
    return CryptoJobTraits::JobName;
417
  }
418
419
6
  void MemoryInfo(MemoryTracker* tracker) const override {
420
6
    tracker->TrackField("params", params_);
421
6
    tracker->TrackField("errors", errors_);
422
  }
423
424
16036
  static void Run(const v8::FunctionCallbackInfo<v8::Value>& args) {
425
16036
    Environment* env = Environment::GetCurrent(args);
426
427
    CryptoJob<CryptoJobTraits>* job;
428
30249
    ASSIGN_OR_RETURN_UNWRAP(&job, args.Holder());
429
16036
    if (job->mode() == kCryptoJobAsync)
430
14213
      return job->ScheduleWork();
431
432
5469
    v8::Local<v8::Value> ret[2];
433
1823
    env->PrintSyncTrace();
434
1823
    job->DoThreadPoolWork();
435
1823
    v8::Maybe<bool> result = job->ToResult(&ret[0], &ret[1]);
436

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

160585
         arg->IsArrayBuffer() ||
695
145792
         arg->IsSharedArrayBuffer();
696
}
697
698
template <typename T>
699
class ArrayBufferOrViewContents {
700
 public:
701
  ArrayBufferOrViewContents() = default;
702
  ArrayBufferOrViewContents(const ArrayBufferOrViewContents&) = delete;
703
  void operator=(const ArrayBufferOrViewContents&) = delete;
704
705
227829
  inline explicit ArrayBufferOrViewContents(v8::Local<v8::Value> buf) {
706
227829
    if (buf.IsEmpty()) {
707
316
      return;
708
    }
709
710
227513
    CHECK(IsAnyByteSource(buf));
711
227513
    if (buf->IsArrayBufferView()) {
712
222633
      auto view = buf.As<v8::ArrayBufferView>();
713
222633
      offset_ = view->ByteOffset();
714
222633
      length_ = view->ByteLength();
715
445266
      data_ = view->Buffer()->Data();
716
4880
    } else if (buf->IsArrayBuffer()) {
717
4856
      auto ab = buf.As<v8::ArrayBuffer>();
718
4856
      offset_ = 0;
719
4856
      length_ = ab->ByteLength();
720
4856
      data_ = ab->Data();
721
    } else {
722
24
      auto sab = buf.As<v8::SharedArrayBuffer>();
723
24
      offset_ = 0;
724
24
      length_ = sab->ByteLength();
725
24
      data_ = sab->Data();
726
    }
727
  }
728
729
20166
  inline const T* data() const {
730
    // Ideally, these would return nullptr if IsEmpty() or length_ is zero,
731
    // but some of the openssl API react badly if given a nullptr even when
732
    // length is zero, so we have to return something.
733
20166
    if (size() == 0)
734
149
      return &buf;
735
20017
    return reinterpret_cast<T*>(data_) + offset_;
736
  }
737
738
103308
  inline T* data() {
739
    // Ideally, these would return nullptr if IsEmpty() or length_ is zero,
740
    // but some of the openssl API react badly if given a nullptr even when
741
    // length is zero, so we have to return something.
742
103308
    if (size() == 0)
743
3
      return &buf;
744
103305
    return reinterpret_cast<T*>(data_) + offset_;
745
  }
746
747
700851
  inline size_t size() const { return length_; }
748
749
  // In most cases, input buffer sizes passed in to openssl need to
750
  // be limited to <= INT_MAX. This utility method helps us check.
751
220025
  inline bool CheckSizeInt32() { return size() <= INT_MAX; }
752
753
5072
  inline ByteSource ToByteSource() const {
754
5072
    return ByteSource::Foreign(data(), size());
755
  }
756
757
14790
  inline ByteSource ToCopy() const {
758
14790
    if (size() == 0) return ByteSource();
759
12102
    ByteSource::Builder buf(size());
760
12102
    memcpy(buf.data<void>(), data(), size());
761
12102
    return std::move(buf).release();
762
  }
763
764
95
  inline ByteSource ToNullTerminatedCopy() const {
765
95
    if (size() == 0) return ByteSource();
766
88
    ByteSource::Builder buf(size() + 1);
767
88
    memcpy(buf.data<void>(), data(), size());
768
88
    buf.data<char>()[size()] = 0;
769
88
    return std::move(buf).release(size());
770
  }
771
772
  template <typename M>
773
104
  void CopyTo(M* dest, size_t len) const {
774
    static_assert(sizeof(M) == 1, "sizeof(M) must equal 1");
775
104
    len = std::min(len, size());
776

104
    if (len > 0 && data() != nullptr)
777
104
      memcpy(dest, data(), len);
778
104
  }
779
780
 private:
781
  T buf = 0;
782
  size_t offset_ = 0;
783
  size_t length_ = 0;
784
  void* data_ = nullptr;
785
786
  // Declaring operator new and delete as deleted is not spec compliant.
787
  // Therefore declare them private instead to disable dynamic alloc
788
  void* operator new(size_t);
789
  void* operator new[](size_t);
790
  void operator delete(void*);
791
  void operator delete[](void*);
792
};
793
794
v8::MaybeLocal<v8::Value> EncodeBignum(
795
    Environment* env,
796
    const BIGNUM* bn,
797
    int size,
798
    v8::Local<v8::Value>* error);
799
800
v8::Maybe<bool> SetEncodedValue(
801
    Environment* env,
802
    v8::Local<v8::Object> target,
803
    v8::Local<v8::String> name,
804
    const BIGNUM* bn,
805
    int size = 0);
806
807
namespace Util {
808
void Initialize(Environment* env, v8::Local<v8::Object> target);
809
void RegisterExternalReferences(ExternalReferenceRegistry* registry);
810
}  // namespace Util
811
812
}  // namespace crypto
813
}  // namespace node
814
815
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
816
#endif  // SRC_CRYPTO_CRYPTO_UTIL_H_