xref: /third_party/node/src/crypto/crypto_util.h (revision 1cb0ef41)
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/dsa.h>
16#include <openssl/ec.h>
17#include <openssl/err.h>
18#include <openssl/evp.h>
19#include <openssl/hmac.h>
20#include <openssl/kdf.h>
21#include <openssl/rsa.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 <climits>
34#include <cstdio>
35#include <memory>
36#include <optional>
37#include <string>
38#include <vector>
39
40namespace node {
41namespace crypto {
42// Currently known sizes of commonly used OpenSSL struct sizes.
43// OpenSSL considers it's various structs to be opaque and the
44// sizes may change from one version of OpenSSL to another, so
45// these values should not be trusted to remain static. These
46// are provided to allow for some close to reasonable memory
47// tracking.
48constexpr size_t kSizeOf_DH = 144;
49constexpr size_t kSizeOf_EC_KEY = 80;
50constexpr size_t kSizeOf_EVP_CIPHER_CTX = 168;
51constexpr size_t kSizeOf_EVP_MD_CTX = 48;
52constexpr size_t kSizeOf_EVP_PKEY = 72;
53constexpr size_t kSizeOf_EVP_PKEY_CTX = 80;
54constexpr size_t kSizeOf_HMAC_CTX = 32;
55
56// Define smart pointers for the most commonly used OpenSSL types:
57using X509Pointer = DeleteFnPtr<X509, X509_free>;
58using BIOPointer = DeleteFnPtr<BIO, BIO_free_all>;
59using SSLCtxPointer = DeleteFnPtr<SSL_CTX, SSL_CTX_free>;
60using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>;
61using SSLPointer = DeleteFnPtr<SSL, SSL_free>;
62using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
63using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>;
64using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
65using EVPMDPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
66using RSAPointer = DeleteFnPtr<RSA, RSA_free>;
67using ECPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
68using BignumPointer = DeleteFnPtr<BIGNUM, BN_free>;
69using BignumCtxPointer = DeleteFnPtr<BN_CTX, BN_CTX_free>;
70using NetscapeSPKIPointer = DeleteFnPtr<NETSCAPE_SPKI, NETSCAPE_SPKI_free>;
71using ECGroupPointer = DeleteFnPtr<EC_GROUP, EC_GROUP_free>;
72using ECPointPointer = DeleteFnPtr<EC_POINT, EC_POINT_free>;
73using ECKeyPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
74using DHPointer = DeleteFnPtr<DH, DH_free>;
75using ECDSASigPointer = DeleteFnPtr<ECDSA_SIG, ECDSA_SIG_free>;
76using HMACCtxPointer = DeleteFnPtr<HMAC_CTX, HMAC_CTX_free>;
77using CipherCtxPointer = DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>;
78using RsaPointer = DeleteFnPtr<RSA, RSA_free>;
79using DsaPointer = DeleteFnPtr<DSA, DSA_free>;
80using DsaSigPointer = DeleteFnPtr<DSA_SIG, DSA_SIG_free>;
81
82// Our custom implementation of the certificate verify callback
83// used when establishing a TLS handshake. Because we cannot perform
84// I/O quickly enough with X509_STORE_CTX_ APIs in this callback,
85// we ignore preverify_ok errors here and let the handshake continue.
86// In other words, this VerifyCallback is a non-op. It is imperative
87// that the user user Connection::VerifyError after the `secure`
88// callback has been made.
89extern int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx);
90
91bool ProcessFipsOptions();
92
93bool InitCryptoOnce(v8::Isolate* isolate);
94void InitCryptoOnce();
95
96void InitCrypto(v8::Local<v8::Object> target);
97
98extern void UseExtraCaCerts(const std::string& file);
99
100// Forcibly clear OpenSSL's error stack on return. This stops stale errors
101// from popping up later in the lifecycle of crypto operations where they
102// would cause spurious failures. It's a rather blunt method, though.
103// ERR_clear_error() isn't necessarily cheap either.
104struct ClearErrorOnReturn {
105  ~ClearErrorOnReturn() { ERR_clear_error(); }
106};
107
108// Pop errors from OpenSSL's error stack that were added
109// between when this was constructed and destructed.
110struct MarkPopErrorOnReturn {
111  MarkPopErrorOnReturn() { ERR_set_mark(); }
112  ~MarkPopErrorOnReturn() { ERR_pop_to_mark(); }
113};
114
115struct CSPRNGResult {
116  const bool ok;
117  MUST_USE_RESULT bool is_ok() const { return ok; }
118  MUST_USE_RESULT bool is_err() const { return !ok; }
119};
120
121// Either succeeds with exactly |length| bytes of cryptographically
122// strong pseudo-random data, or fails. This function may block.
123// Don't assume anything about the contents of |buffer| on error.
124// As a special case, |length == 0| can be used to check if the CSPRNG
125// is properly seeded without consuming entropy.
126MUST_USE_RESULT CSPRNGResult CSPRNG(void* buffer, size_t length);
127
128int PasswordCallback(char* buf, int size, int rwflag, void* u);
129
130int NoPasswordCallback(char* buf, int size, int rwflag, void* u);
131
132// Decode is used by the various stream-based crypto utilities to decode
133// string input.
134template <typename T>
135void Decode(const v8::FunctionCallbackInfo<v8::Value>& args,
136            void (*callback)(T*, const v8::FunctionCallbackInfo<v8::Value>&,
137                             const char*, size_t)) {
138  T* ctx;
139  ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
140
141  if (args[0]->IsString()) {
142    StringBytes::InlineDecoder decoder;
143    Environment* env = Environment::GetCurrent(args);
144    enum encoding enc = ParseEncoding(env->isolate(), args[1], UTF8);
145    if (decoder.Decode(env, args[0].As<v8::String>(), enc).IsNothing())
146      return;
147    callback(ctx, args, decoder.out(), decoder.size());
148  } else {
149    ArrayBufferViewContents<char> buf(args[0]);
150    callback(ctx, args, buf.data(), buf.length());
151  }
152}
153
154#define NODE_CRYPTO_ERROR_CODES_MAP(V)                                        \
155    V(CIPHER_JOB_FAILED, "Cipher job failed")                                 \
156    V(DERIVING_BITS_FAILED, "Deriving bits failed")                           \
157    V(ENGINE_NOT_FOUND, "Engine \"%s\" was not found")                        \
158    V(INVALID_KEY_TYPE, "Invalid key type")                                   \
159    V(KEY_GENERATION_JOB_FAILED, "Key generation job failed")                 \
160    V(OK, "Ok")                                                               \
161
162enum class NodeCryptoError {
163#define V(CODE, DESCRIPTION) CODE,
164  NODE_CRYPTO_ERROR_CODES_MAP(V)
165#undef V
166};
167
168// Utility struct used to harvest error information from openssl's error stack
169struct CryptoErrorStore final : public MemoryRetainer {
170 public:
171  void Capture();
172
173  bool Empty() const;
174
175  template <typename... Args>
176  void Insert(const NodeCryptoError error, Args&&... args);
177
178  v8::MaybeLocal<v8::Value> ToException(
179      Environment* env,
180      v8::Local<v8::String> exception_string = v8::Local<v8::String>()) const;
181
182  SET_NO_MEMORY_INFO()
183  SET_MEMORY_INFO_NAME(CryptoErrorStore)
184  SET_SELF_SIZE(CryptoErrorStore)
185
186 private:
187  std::vector<std::string> errors_;
188};
189
190template <typename... Args>
191void CryptoErrorStore::Insert(const NodeCryptoError error, Args&&... args) {
192  const char* error_string = nullptr;
193  switch (error) {
194#define V(CODE, DESCRIPTION) \
195    case NodeCryptoError::CODE: error_string = DESCRIPTION; break;
196    NODE_CRYPTO_ERROR_CODES_MAP(V)
197#undef V
198  }
199  errors_.emplace_back(SPrintF(error_string,
200                               std::forward<Args>(args)...));
201}
202
203template <typename T>
204T* MallocOpenSSL(size_t count) {
205  void* mem = OPENSSL_malloc(MultiplyWithOverflowCheck(count, sizeof(T)));
206  CHECK_IMPLIES(mem == nullptr, count == 0);
207  return static_cast<T*>(mem);
208}
209
210// A helper class representing a read-only byte array. When deallocated, its
211// contents are zeroed.
212class ByteSource {
213 public:
214  class Builder {
215   public:
216    // Allocates memory using OpenSSL's memory allocator.
217    explicit Builder(size_t size)
218        : data_(MallocOpenSSL<char>(size)), size_(size) {}
219
220    Builder(Builder&& other) = delete;
221    Builder& operator=(Builder&& other) = delete;
222    Builder(const Builder&) = delete;
223    Builder& operator=(const Builder&) = delete;
224
225    ~Builder() { OPENSSL_clear_free(data_, size_); }
226
227    // Returns the underlying non-const pointer.
228    template <typename T>
229    T* data() {
230      return reinterpret_cast<T*>(data_);
231    }
232
233    // Returns the (allocated) size in bytes.
234    size_t size() const { return size_; }
235
236    // Finalizes the Builder and returns a read-only view that is optionally
237    // truncated.
238    ByteSource release(std::optional<size_t> resize = std::nullopt) && {
239      if (resize) {
240        CHECK_LE(*resize, size_);
241        if (*resize == 0) {
242          OPENSSL_clear_free(data_, size_);
243          data_ = nullptr;
244        }
245        size_ = *resize;
246      }
247      ByteSource out = ByteSource::Allocated(data_, size_);
248      data_ = nullptr;
249      size_ = 0;
250      return out;
251    }
252
253   private:
254    void* data_;
255    size_t size_;
256  };
257
258  ByteSource() = default;
259  ByteSource(ByteSource&& other) noexcept;
260  ~ByteSource();
261
262  ByteSource& operator=(ByteSource&& other) noexcept;
263
264  ByteSource(const ByteSource&) = delete;
265  ByteSource& operator=(const ByteSource&) = delete;
266
267  template <typename T = void>
268  const T* data() const {
269    return reinterpret_cast<const T*>(data_);
270  }
271
272  size_t size() const { return size_; }
273
274  operator bool() const { return data_ != nullptr; }
275
276  BignumPointer ToBN() const {
277    return BignumPointer(BN_bin2bn(data<unsigned char>(), size(), nullptr));
278  }
279
280  // Creates a v8::BackingStore that takes over responsibility for
281  // any allocated data. The ByteSource will be reset with size = 0
282  // after being called.
283  std::unique_ptr<v8::BackingStore> ReleaseToBackingStore();
284
285  v8::Local<v8::ArrayBuffer> ToArrayBuffer(Environment* env);
286
287  v8::MaybeLocal<v8::Uint8Array> ToBuffer(Environment* env);
288
289  static ByteSource Allocated(void* data, size_t size);
290  static ByteSource Foreign(const void* data, size_t size);
291
292  static ByteSource FromEncodedString(Environment* env,
293                                      v8::Local<v8::String> value,
294                                      enum encoding enc = BASE64);
295
296  static ByteSource FromStringOrBuffer(Environment* env,
297                                       v8::Local<v8::Value> value);
298
299  static ByteSource FromString(Environment* env,
300                               v8::Local<v8::String> str,
301                               bool ntc = false);
302
303  static ByteSource FromBuffer(v8::Local<v8::Value> buffer,
304                               bool ntc = false);
305
306  static ByteSource FromBIO(const BIOPointer& bio);
307
308  static ByteSource NullTerminatedCopy(Environment* env,
309                                       v8::Local<v8::Value> value);
310
311  static ByteSource FromSymmetricKeyObjectHandle(v8::Local<v8::Value> handle);
312
313  static ByteSource FromSecretKeyBytes(
314      Environment* env, v8::Local<v8::Value> value);
315
316 private:
317  const void* data_ = nullptr;
318  void* allocated_data_ = nullptr;
319  size_t size_ = 0;
320
321  ByteSource(const void* data, void* allocated_data, size_t size)
322      : data_(data), allocated_data_(allocated_data), size_(size) {}
323};
324
325enum CryptoJobMode {
326  kCryptoJobAsync,
327  kCryptoJobSync
328};
329
330CryptoJobMode GetCryptoJobMode(v8::Local<v8::Value> args);
331
332template <typename CryptoJobTraits>
333class CryptoJob : public AsyncWrap, public ThreadPoolWork {
334 public:
335  using AdditionalParams = typename CryptoJobTraits::AdditionalParameters;
336
337  explicit CryptoJob(Environment* env,
338                     v8::Local<v8::Object> object,
339                     AsyncWrap::ProviderType type,
340                     CryptoJobMode mode,
341                     AdditionalParams&& params)
342      : AsyncWrap(env, object, type),
343        ThreadPoolWork(env, "crypto"),
344        mode_(mode),
345        params_(std::move(params)) {
346    // If the CryptoJob is async, then the instance will be
347    // cleaned up when AfterThreadPoolWork is called.
348    if (mode == kCryptoJobSync) MakeWeak();
349  }
350
351  bool IsNotIndicativeOfMemoryLeakAtExit() const override {
352    // CryptoJobs run a work in the libuv thread pool and may still
353    // exist when the event loop empties and starts to exit.
354    return true;
355  }
356
357  void AfterThreadPoolWork(int status) override {
358    Environment* env = AsyncWrap::env();
359    CHECK_EQ(mode_, kCryptoJobAsync);
360    CHECK(status == 0 || status == UV_ECANCELED);
361    std::unique_ptr<CryptoJob> ptr(this);
362    // If the job was canceled do not execute the callback.
363    // TODO(@jasnell): We should likely revisit skipping the
364    // callback on cancel as that could leave the JS in a pending
365    // state (e.g. unresolved promises...)
366    if (status == UV_ECANCELED) return;
367    v8::HandleScope handle_scope(env->isolate());
368    v8::Context::Scope context_scope(env->context());
369
370    // TODO(tniessen): Remove the exception handling logic here as soon as we
371    // can verify that no code path in ToResult will ever throw an exception.
372    v8::Local<v8::Value> exception;
373    v8::Local<v8::Value> args[2];
374    {
375      node::errors::TryCatchScope try_catch(env);
376      v8::Maybe<bool> ret = ptr->ToResult(&args[0], &args[1]);
377      if (!ret.IsJust()) {
378        CHECK(try_catch.HasCaught());
379        exception = try_catch.Exception();
380      } else if (!ret.FromJust()) {
381        return;
382      }
383    }
384
385    if (exception.IsEmpty()) {
386      ptr->MakeCallback(env->ondone_string(), arraysize(args), args);
387    } else {
388      ptr->MakeCallback(env->ondone_string(), 1, &exception);
389    }
390  }
391
392  virtual v8::Maybe<bool> ToResult(
393      v8::Local<v8::Value>* err,
394      v8::Local<v8::Value>* result) = 0;
395
396  CryptoJobMode mode() const { return mode_; }
397
398  CryptoErrorStore* errors() { return &errors_; }
399
400  AdditionalParams* params() { return &params_; }
401
402  const char* MemoryInfoName() const override {
403    return CryptoJobTraits::JobName;
404  }
405
406  void MemoryInfo(MemoryTracker* tracker) const override {
407    tracker->TrackField("params", params_);
408    tracker->TrackField("errors", errors_);
409  }
410
411  static void Run(const v8::FunctionCallbackInfo<v8::Value>& args) {
412    Environment* env = Environment::GetCurrent(args);
413
414    CryptoJob<CryptoJobTraits>* job;
415    ASSIGN_OR_RETURN_UNWRAP(&job, args.Holder());
416    if (job->mode() == kCryptoJobAsync)
417      return job->ScheduleWork();
418
419    v8::Local<v8::Value> ret[2];
420    env->PrintSyncTrace();
421    job->DoThreadPoolWork();
422    v8::Maybe<bool> result = job->ToResult(&ret[0], &ret[1]);
423    if (result.IsJust() && result.FromJust()) {
424      args.GetReturnValue().Set(
425          v8::Array::New(env->isolate(), ret, arraysize(ret)));
426    }
427  }
428
429  static void Initialize(
430      v8::FunctionCallback new_fn,
431      Environment* env,
432      v8::Local<v8::Object> target) {
433    v8::Isolate* isolate = env->isolate();
434    v8::HandleScope scope(isolate);
435    v8::Local<v8::Context> context = env->context();
436    v8::Local<v8::FunctionTemplate> job = NewFunctionTemplate(isolate, new_fn);
437    job->Inherit(AsyncWrap::GetConstructorTemplate(env));
438    job->InstanceTemplate()->SetInternalFieldCount(
439        AsyncWrap::kInternalFieldCount);
440    SetProtoMethod(isolate, job, "run", Run);
441    SetConstructorFunction(context, target, CryptoJobTraits::JobName, job);
442  }
443
444  static void RegisterExternalReferences(v8::FunctionCallback new_fn,
445                                         ExternalReferenceRegistry* registry) {
446    registry->Register(new_fn);
447    registry->Register(Run);
448  }
449
450 private:
451  const CryptoJobMode mode_;
452  CryptoErrorStore errors_;
453  AdditionalParams params_;
454};
455
456template <typename DeriveBitsTraits>
457class DeriveBitsJob final : public CryptoJob<DeriveBitsTraits> {
458 public:
459  using AdditionalParams = typename DeriveBitsTraits::AdditionalParameters;
460
461  static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
462    Environment* env = Environment::GetCurrent(args);
463
464    CryptoJobMode mode = GetCryptoJobMode(args[0]);
465
466    AdditionalParams params;
467    if (DeriveBitsTraits::AdditionalConfig(mode, args, 1, &params)
468            .IsNothing()) {
469      // The DeriveBitsTraits::AdditionalConfig is responsible for
470      // calling an appropriate THROW_CRYPTO_* variant reporting
471      // whatever error caused initialization to fail.
472      return;
473    }
474
475    new DeriveBitsJob(env, args.This(), mode, std::move(params));
476  }
477
478  static void Initialize(
479      Environment* env,
480      v8::Local<v8::Object> target) {
481    CryptoJob<DeriveBitsTraits>::Initialize(New, env, target);
482  }
483
484  static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
485    CryptoJob<DeriveBitsTraits>::RegisterExternalReferences(New, registry);
486  }
487
488  DeriveBitsJob(
489      Environment* env,
490      v8::Local<v8::Object> object,
491      CryptoJobMode mode,
492      AdditionalParams&& params)
493      : CryptoJob<DeriveBitsTraits>(
494            env,
495            object,
496            DeriveBitsTraits::Provider,
497            mode,
498            std::move(params)) {}
499
500  void DoThreadPoolWork() override {
501    if (!DeriveBitsTraits::DeriveBits(
502            AsyncWrap::env(),
503            *CryptoJob<DeriveBitsTraits>::params(), &out_)) {
504      CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors();
505      errors->Capture();
506      if (errors->Empty())
507        errors->Insert(NodeCryptoError::DERIVING_BITS_FAILED);
508      return;
509    }
510    success_ = true;
511  }
512
513  v8::Maybe<bool> ToResult(
514      v8::Local<v8::Value>* err,
515      v8::Local<v8::Value>* result) override {
516    Environment* env = AsyncWrap::env();
517    CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors();
518    if (success_) {
519      CHECK(errors->Empty());
520      *err = v8::Undefined(env->isolate());
521      return DeriveBitsTraits::EncodeOutput(
522          env,
523          *CryptoJob<DeriveBitsTraits>::params(),
524          &out_,
525          result);
526    }
527
528    if (errors->Empty())
529      errors->Capture();
530    CHECK(!errors->Empty());
531    *result = v8::Undefined(env->isolate());
532    return v8::Just(errors->ToException(env).ToLocal(err));
533  }
534
535  SET_SELF_SIZE(DeriveBitsJob)
536  void MemoryInfo(MemoryTracker* tracker) const override {
537    tracker->TrackFieldWithSize("out", out_.size());
538    CryptoJob<DeriveBitsTraits>::MemoryInfo(tracker);
539  }
540
541 private:
542  ByteSource out_;
543  bool success_ = false;
544};
545
546void ThrowCryptoError(Environment* env,
547                      unsigned long err,  // NOLINT(runtime/int)
548                      const char* message = nullptr);
549
550#ifndef OPENSSL_NO_ENGINE
551struct EnginePointer {
552  ENGINE* engine = nullptr;
553  bool finish_on_exit = false;
554
555  inline EnginePointer() = default;
556
557  inline explicit EnginePointer(ENGINE* engine_, bool finish_on_exit_ = false)
558    : engine(engine_),
559      finish_on_exit(finish_on_exit_) {}
560
561  inline EnginePointer(EnginePointer&& other) noexcept
562      : engine(other.engine),
563        finish_on_exit(other.finish_on_exit) {
564    other.release();
565  }
566
567  inline ~EnginePointer() { reset(); }
568
569  inline EnginePointer& operator=(EnginePointer&& other) noexcept {
570    if (this == &other) return *this;
571    this->~EnginePointer();
572    return *new (this) EnginePointer(std::move(other));
573  }
574
575  inline operator bool() const { return engine != nullptr; }
576
577  inline ENGINE* get() { return engine; }
578
579  inline void reset(ENGINE* engine_ = nullptr, bool finish_on_exit_ = false) {
580    if (engine != nullptr) {
581      if (finish_on_exit) {
582        // This also does the equivalent of ENGINE_free.
583        CHECK_EQ(ENGINE_finish(engine), 1);
584      } else {
585        CHECK_EQ(ENGINE_free(engine), 1);
586      }
587    }
588    engine = engine_;
589    finish_on_exit = finish_on_exit_;
590  }
591
592  inline ENGINE* release() {
593    ENGINE* ret = engine;
594    engine = nullptr;
595    finish_on_exit = false;
596    return ret;
597  }
598};
599
600EnginePointer LoadEngineById(const char* id, CryptoErrorStore* errors);
601
602bool SetEngine(
603    const char* id,
604    uint32_t flags,
605    CryptoErrorStore* errors = nullptr);
606
607void SetEngine(const v8::FunctionCallbackInfo<v8::Value>& args);
608#endif  // !OPENSSL_NO_ENGINE
609
610void GetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
611
612void SetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
613
614void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
615
616class CipherPushContext {
617 public:
618  inline explicit CipherPushContext(Environment* env) : env_(env) {}
619
620  inline void push_back(const char* str) {
621    list_.emplace_back(OneByteString(env_->isolate(), str));
622  }
623
624  inline v8::Local<v8::Array> ToJSArray() {
625    return v8::Array::New(env_->isolate(), list_.data(), list_.size());
626  }
627
628 private:
629  std::vector<v8::Local<v8::Value>> list_;
630  Environment* env_;
631};
632
633#if OPENSSL_VERSION_MAJOR >= 3
634template <class TypeName,
635          TypeName* fetch_type(OSSL_LIB_CTX*, const char*, const char*),
636          void free_type(TypeName*),
637          const TypeName* getbyname(const char*),
638          const char* getname(const TypeName*)>
639void array_push_back(const TypeName* evp_ref,
640                     const char* from,
641                     const char* to,
642                     void* arg) {
643  if (!from)
644    return;
645
646  const TypeName* real_instance = getbyname(from);
647  if (!real_instance)
648    return;
649
650  const char* real_name = getname(real_instance);
651  if (!real_name)
652    return;
653
654  // EVP_*_fetch() does not support alias names, so we need to pass it the
655  // real/original algorithm name.
656  // We use EVP_*_fetch() as a filter here because it will only return an
657  // instance if the algorithm is supported by the public OpenSSL APIs (some
658  // algorithms are used internally by OpenSSL and are also passed to this
659  // callback).
660  TypeName* fetched = fetch_type(nullptr, real_name, nullptr);
661  if (!fetched)
662    return;
663
664  free_type(fetched);
665  static_cast<CipherPushContext*>(arg)->push_back(from);
666}
667#else
668template <class TypeName>
669void array_push_back(const TypeName* evp_ref,
670                     const char* from,
671                     const char* to,
672                     void* arg) {
673  if (!from)
674    return;
675  static_cast<CipherPushContext*>(arg)->push_back(from);
676}
677#endif
678
679inline bool IsAnyByteSource(v8::Local<v8::Value> arg) {
680  return arg->IsArrayBufferView() ||
681         arg->IsArrayBuffer() ||
682         arg->IsSharedArrayBuffer();
683}
684
685template <typename T>
686class ArrayBufferOrViewContents {
687 public:
688  ArrayBufferOrViewContents() = default;
689  ArrayBufferOrViewContents(const ArrayBufferOrViewContents&) = delete;
690  void operator=(const ArrayBufferOrViewContents&) = delete;
691
692  inline explicit ArrayBufferOrViewContents(v8::Local<v8::Value> buf) {
693    if (buf.IsEmpty()) {
694      return;
695    }
696
697    CHECK(IsAnyByteSource(buf));
698    if (buf->IsArrayBufferView()) {
699      auto view = buf.As<v8::ArrayBufferView>();
700      offset_ = view->ByteOffset();
701      length_ = view->ByteLength();
702      data_ = view->Buffer()->Data();
703    } else if (buf->IsArrayBuffer()) {
704      auto ab = buf.As<v8::ArrayBuffer>();
705      offset_ = 0;
706      length_ = ab->ByteLength();
707      data_ = ab->Data();
708    } else {
709      auto sab = buf.As<v8::SharedArrayBuffer>();
710      offset_ = 0;
711      length_ = sab->ByteLength();
712      data_ = sab->Data();
713    }
714  }
715
716  inline const T* data() const {
717    // Ideally, these would return nullptr if IsEmpty() or length_ is zero,
718    // but some of the openssl API react badly if given a nullptr even when
719    // length is zero, so we have to return something.
720    if (size() == 0)
721      return &buf;
722    return reinterpret_cast<T*>(data_) + offset_;
723  }
724
725  inline T* data() {
726    // Ideally, these would return nullptr if IsEmpty() or length_ is zero,
727    // but some of the openssl API react badly if given a nullptr even when
728    // length is zero, so we have to return something.
729    if (size() == 0)
730      return &buf;
731    return reinterpret_cast<T*>(data_) + offset_;
732  }
733
734  inline size_t size() const { return length_; }
735
736  // In most cases, input buffer sizes passed in to openssl need to
737  // be limited to <= INT_MAX. This utility method helps us check.
738  inline bool CheckSizeInt32() { return size() <= INT_MAX; }
739
740  inline ByteSource ToByteSource() const {
741    return ByteSource::Foreign(data(), size());
742  }
743
744  inline ByteSource ToCopy() const {
745    if (size() == 0) return ByteSource();
746    ByteSource::Builder buf(size());
747    memcpy(buf.data<void>(), data(), size());
748    return std::move(buf).release();
749  }
750
751  inline ByteSource ToNullTerminatedCopy() const {
752    if (size() == 0) return ByteSource();
753    ByteSource::Builder buf(size() + 1);
754    memcpy(buf.data<void>(), data(), size());
755    buf.data<char>()[size()] = 0;
756    return std::move(buf).release(size());
757  }
758
759  template <typename M>
760  void CopyTo(M* dest, size_t len) const {
761    static_assert(sizeof(M) == 1, "sizeof(M) must equal 1");
762    len = std::min(len, size());
763    if (len > 0 && data() != nullptr)
764      memcpy(dest, data(), len);
765  }
766
767 private:
768  T buf = 0;
769  size_t offset_ = 0;
770  size_t length_ = 0;
771  void* data_ = nullptr;
772
773  // Declaring operator new and delete as deleted is not spec compliant.
774  // Therefore declare them private instead to disable dynamic alloc
775  void* operator new(size_t);
776  void* operator new[](size_t);
777  void operator delete(void*);
778  void operator delete[](void*);
779};
780
781v8::MaybeLocal<v8::Value> EncodeBignum(
782    Environment* env,
783    const BIGNUM* bn,
784    int size,
785    v8::Local<v8::Value>* error);
786
787v8::Maybe<bool> SetEncodedValue(
788    Environment* env,
789    v8::Local<v8::Object> target,
790    v8::Local<v8::String> name,
791    const BIGNUM* bn,
792    int size = 0);
793
794bool SetRsaOaepLabel(const EVPKeyCtxPointer& rsa, const ByteSource& label);
795
796namespace Util {
797void Initialize(Environment* env, v8::Local<v8::Object> target);
798void RegisterExternalReferences(ExternalReferenceRegistry* registry);
799}  // namespace Util
800
801}  // namespace crypto
802}  // namespace node
803
804#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
805#endif  // SRC_CRYPTO_CRYPTO_UTIL_H_
806