GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_util.h Lines: 245 254 96.5 %
Date: 2022-11-20 04:28:36 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
11214
  ~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
26009
  MarkPopErrorOnReturn() { ERR_set_mark(); }
111
26008
  ~MarkPopErrorOnReturn() { ERR_pop_to_mark(); }
112
};
113
114
struct CSPRNGResult {
115
  const bool ok;
116
24557
  MUST_USE_RESULT bool is_ok() const { return ok; }
117
9917
  MUST_USE_RESULT bool is_err() const { return !ok; }
118
};
119
120
// Either succeeds with exactly |length| bytes of cryptographically
121
// strong pseudo-random data, or fails. This function may block.
122
// Don't assume anything about the contents of |buffer| on error.
123
// As a special case, |length == 0| can be used to check if the CSPRNG
124
// is properly seeded without consuming entropy.
125
MUST_USE_RESULT CSPRNGResult CSPRNG(void* buffer, size_t length);
126
127
int PasswordCallback(char* buf, int size, int rwflag, void* u);
128
129
int NoPasswordCallback(char* buf, int size, int rwflag, void* u);
130
131
// Decode is used by the various stream-based crypto utilities to decode
132
// string input.
133
template <typename T>
134
3712
void Decode(const v8::FunctionCallbackInfo<v8::Value>& args,
135
            void (*callback)(T*, const v8::FunctionCallbackInfo<v8::Value>&,
136
                             const char*, size_t)) {
137
  T* ctx;
138
3712
  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
139
140
7424
  if (args[0]->IsString()) {
141
1854
    StringBytes::InlineDecoder decoder;
142
1854
    Environment* env = Environment::GetCurrent(args);
143
1854
    enum encoding enc = ParseEncoding(env->isolate(), args[1], UTF8);
144
5562
    if (decoder.Decode(env, args[0].As<v8::String>(), enc).IsNothing())
145
      return;
146
1854
    callback(ctx, args, decoder.out(), decoder.size());
147
  } else {
148
1858
    ArrayBufferViewContents<char> buf(args[0]);
149
1858
    callback(ctx, args, buf.data(), buf.length());
150
  }
151
}
152
153
#define NODE_CRYPTO_ERROR_CODES_MAP(V)                                        \
154
    V(CIPHER_JOB_FAILED, "Cipher job failed")                                 \
155
    V(DERIVING_BITS_FAILED, "Deriving bits failed")                           \
156
    V(ENGINE_NOT_FOUND, "Engine \"%s\" was not found")                        \
157
    V(INVALID_KEY_TYPE, "Invalid key type")                                   \
158
    V(KEY_GENERATION_JOB_FAILED, "Key generation job failed")                 \
159
    V(OK, "Ok")                                                               \
160
161
enum class NodeCryptoError {
162
#define V(CODE, DESCRIPTION) CODE,
163
  NODE_CRYPTO_ERROR_CODES_MAP(V)
164
#undef V
165
};
166
167
// Utility struct used to harvest error information from openssl's error stack
168
struct CryptoErrorStore final : public MemoryRetainer {
169
 public:
170
  void Capture();
171
172
  bool Empty() const;
173
174
  template <typename... Args>
175
  void Insert(const NodeCryptoError error, Args&&... args);
176
177
  v8::MaybeLocal<v8::Value> ToException(
178
      Environment* env,
179
      v8::Local<v8::String> exception_string = v8::Local<v8::String>()) const;
180
181
3
  SET_NO_MEMORY_INFO()
182
3
  SET_MEMORY_INFO_NAME(CryptoErrorStore)
183
3
  SET_SELF_SIZE(CryptoErrorStore)
184
185
 private:
186
  std::vector<std::string> errors_;
187
};
188
189
template <typename... Args>
190
14
void CryptoErrorStore::Insert(const NodeCryptoError error, Args&&... args) {
191
14
  const char* error_string = nullptr;
192

14
  switch (error) {
193
#define V(CODE, DESCRIPTION) \
194
    case NodeCryptoError::CODE: error_string = DESCRIPTION; break;
195
14
    NODE_CRYPTO_ERROR_CODES_MAP(V)
196
#undef V
197
  }
198
14
  errors_.emplace_back(SPrintF(error_string,
199
                               std::forward<Args>(args)...));
200
14
}
201
202
template <typename T>
203
24961
T* MallocOpenSSL(size_t count) {
204
24961
  void* mem = OPENSSL_malloc(MultiplyWithOverflowCheck(count, sizeof(T)));
205

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

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

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

160645
         arg->IsArrayBuffer() ||
681
145837
         arg->IsSharedArrayBuffer();
682
}
683
684
template <typename T>
685
class ArrayBufferOrViewContents {
686
 public:
687
  ArrayBufferOrViewContents() = default;
688
  ArrayBufferOrViewContents(const ArrayBufferOrViewContents&) = delete;
689
  void operator=(const ArrayBufferOrViewContents&) = delete;
690
691
227864
  inline explicit ArrayBufferOrViewContents(v8::Local<v8::Value> buf) {
692
227864
    if (buf.IsEmpty()) {
693
320
      return;
694
    }
695
696
227544
    CHECK(IsAnyByteSource(buf));
697
227544
    if (buf->IsArrayBufferView()) {
698
222658
      auto view = buf.As<v8::ArrayBufferView>();
699
222658
      offset_ = view->ByteOffset();
700
222658
      length_ = view->ByteLength();
701
445316
      data_ = view->Buffer()->Data();
702
4886
    } else if (buf->IsArrayBuffer()) {
703
4862
      auto ab = buf.As<v8::ArrayBuffer>();
704
4862
      offset_ = 0;
705
4862
      length_ = ab->ByteLength();
706
4862
      data_ = ab->Data();
707
    } else {
708
24
      auto sab = buf.As<v8::SharedArrayBuffer>();
709
24
      offset_ = 0;
710
24
      length_ = sab->ByteLength();
711
24
      data_ = sab->Data();
712
    }
713
  }
714
715
20489
  inline const T* data() const {
716
    // Ideally, these would return nullptr if IsEmpty() or length_ is zero,
717
    // but some of the openssl API react badly if given a nullptr even when
718
    // length is zero, so we have to return something.
719
20489
    if (size() == 0)
720
455
      return &buf;
721
20034
    return reinterpret_cast<T*>(data_) + offset_;
722
  }
723
724
103313
  inline T* data() {
725
    // Ideally, these would return nullptr if IsEmpty() or length_ is zero,
726
    // but some of the openssl API react badly if given a nullptr even when
727
    // length is zero, so we have to return something.
728
103313
    if (size() == 0)
729
3
      return &buf;
730
103310
    return reinterpret_cast<T*>(data_) + offset_;
731
  }
732
733
701245
  inline size_t size() const { return length_; }
734
735
  // In most cases, input buffer sizes passed in to openssl need to
736
  // be limited to <= INT_MAX. This utility method helps us check.
737
220047
  inline bool CheckSizeInt32() { return size() <= INT_MAX; }
738
739
5231
  inline ByteSource ToByteSource() const {
740
5231
    return ByteSource::Foreign(data(), size());
741
  }
742
743
14807
  inline ByteSource ToCopy() const {
744
14807
    if (size() == 0) return ByteSource();
745
12107
    ByteSource::Builder buf(size());
746
12107
    memcpy(buf.data<void>(), data(), size());
747
12107
    return std::move(buf).release();
748
  }
749
750
97
  inline ByteSource ToNullTerminatedCopy() const {
751
97
    if (size() == 0) return ByteSource();
752
90
    ByteSource::Builder buf(size() + 1);
753
90
    memcpy(buf.data<void>(), data(), size());
754
90
    buf.data<char>()[size()] = 0;
755
90
    return std::move(buf).release(size());
756
  }
757
758
  template <typename M>
759
104
  void CopyTo(M* dest, size_t len) const {
760
    static_assert(sizeof(M) == 1, "sizeof(M) must equal 1");
761
104
    len = std::min(len, size());
762

104
    if (len > 0 && data() != nullptr)
763
104
      memcpy(dest, data(), len);
764
104
  }
765
766
 private:
767
  T buf = 0;
768
  size_t offset_ = 0;
769
  size_t length_ = 0;
770
  void* data_ = nullptr;
771
772
  // Declaring operator new and delete as deleted is not spec compliant.
773
  // Therefore declare them private instead to disable dynamic alloc
774
  void* operator new(size_t);
775
  void* operator new[](size_t);
776
  void operator delete(void*);
777
  void operator delete[](void*);
778
};
779
780
v8::MaybeLocal<v8::Value> EncodeBignum(
781
    Environment* env,
782
    const BIGNUM* bn,
783
    int size,
784
    v8::Local<v8::Value>* error);
785
786
v8::Maybe<bool> SetEncodedValue(
787
    Environment* env,
788
    v8::Local<v8::Object> target,
789
    v8::Local<v8::String> name,
790
    const BIGNUM* bn,
791
    int size = 0);
792
793
bool SetRsaOaepLabel(const EVPKeyCtxPointer& rsa, const ByteSource& label);
794
795
namespace Util {
796
void Initialize(Environment* env, v8::Local<v8::Object> target);
797
void RegisterExternalReferences(ExternalReferenceRegistry* registry);
798
}  // namespace Util
799
800
}  // namespace crypto
801
}  // namespace node
802
803
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
804
#endif  // SRC_CRYPTO_CRYPTO_UTIL_H_