• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
40 namespace node {
41 namespace 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.
48 constexpr size_t kSizeOf_DH = 144;
49 constexpr size_t kSizeOf_EC_KEY = 80;
50 constexpr size_t kSizeOf_EVP_CIPHER_CTX = 168;
51 constexpr size_t kSizeOf_EVP_MD_CTX = 48;
52 constexpr size_t kSizeOf_EVP_PKEY = 72;
53 constexpr size_t kSizeOf_EVP_PKEY_CTX = 80;
54 constexpr size_t kSizeOf_HMAC_CTX = 32;
55 
56 // Define smart pointers for the most commonly used OpenSSL types:
57 using X509Pointer = DeleteFnPtr<X509, X509_free>;
58 using BIOPointer = DeleteFnPtr<BIO, BIO_free_all>;
59 using SSLCtxPointer = DeleteFnPtr<SSL_CTX, SSL_CTX_free>;
60 using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>;
61 using SSLPointer = DeleteFnPtr<SSL, SSL_free>;
62 using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
63 using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>;
64 using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
65 using EVPMDPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
66 using RSAPointer = DeleteFnPtr<RSA, RSA_free>;
67 using ECPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
68 using BignumPointer = DeleteFnPtr<BIGNUM, BN_free>;
69 using BignumCtxPointer = DeleteFnPtr<BN_CTX, BN_CTX_free>;
70 using NetscapeSPKIPointer = DeleteFnPtr<NETSCAPE_SPKI, NETSCAPE_SPKI_free>;
71 using ECGroupPointer = DeleteFnPtr<EC_GROUP, EC_GROUP_free>;
72 using ECPointPointer = DeleteFnPtr<EC_POINT, EC_POINT_free>;
73 using ECKeyPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
74 using DHPointer = DeleteFnPtr<DH, DH_free>;
75 using ECDSASigPointer = DeleteFnPtr<ECDSA_SIG, ECDSA_SIG_free>;
76 using HMACCtxPointer = DeleteFnPtr<HMAC_CTX, HMAC_CTX_free>;
77 using CipherCtxPointer = DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>;
78 using RsaPointer = DeleteFnPtr<RSA, RSA_free>;
79 using DsaPointer = DeleteFnPtr<DSA, DSA_free>;
80 using 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.
89 extern int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx);
90 
91 bool ProcessFipsOptions();
92 
93 bool InitCryptoOnce(v8::Isolate* isolate);
94 void InitCryptoOnce();
95 
96 void InitCrypto(v8::Local<v8::Object> target);
97 
98 extern 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.
104 struct ClearErrorOnReturn {
~ClearErrorOnReturnClearErrorOnReturn105   ~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.
110 struct MarkPopErrorOnReturn {
MarkPopErrorOnReturnMarkPopErrorOnReturn111   MarkPopErrorOnReturn() { ERR_set_mark(); }
~MarkPopErrorOnReturnMarkPopErrorOnReturn112   ~MarkPopErrorOnReturn() { ERR_pop_to_mark(); }
113 };
114 
115 struct CSPRNGResult {
116   const bool ok;
is_okCSPRNGResult117   MUST_USE_RESULT bool is_ok() const { return ok; }
is_errCSPRNGResult118   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.
126 MUST_USE_RESULT CSPRNGResult CSPRNG(void* buffer, size_t length);
127 
128 int PasswordCallback(char* buf, int size, int rwflag, void* u);
129 
130 int 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.
134 template <typename T>
Decode(const v8::FunctionCallbackInfo<v8::Value> & args,void (* callback)(T *,const v8::FunctionCallbackInfo<v8::Value> &,const char *,size_t))135 void 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 
162 enum 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
169 struct 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 
190 template <typename... Args>
Insert(const NodeCryptoError error,Args &&...args)191 void 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 
203 template <typename T>
MallocOpenSSL(size_t count)204 T* 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.
212 class ByteSource {
213  public:
214   class Builder {
215    public:
216     // Allocates memory using OpenSSL's memory allocator.
Builder(size_t size)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 
~Builder()225     ~Builder() { OPENSSL_clear_free(data_, size_); }
226 
227     // Returns the underlying non-const pointer.
228     template <typename T>
data()229     T* data() {
230       return reinterpret_cast<T*>(data_);
231     }
232 
233     // Returns the (allocated) size in bytes.
size()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>
data()268   const T* data() const {
269     return reinterpret_cast<const T*>(data_);
270   }
271 
size()272   size_t size() const { return size_; }
273 
274   operator bool() const { return data_ != nullptr; }
275 
ToBN()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 
ByteSource(const void * data,void * allocated_data,size_t size)321   ByteSource(const void* data, void* allocated_data, size_t size)
322       : data_(data), allocated_data_(allocated_data), size_(size) {}
323 };
324 
325 enum CryptoJobMode {
326   kCryptoJobAsync,
327   kCryptoJobSync
328 };
329 
330 CryptoJobMode GetCryptoJobMode(v8::Local<v8::Value> args);
331 
332 template <typename CryptoJobTraits>
333 class CryptoJob : public AsyncWrap, public ThreadPoolWork {
334  public:
335   using AdditionalParams = typename CryptoJobTraits::AdditionalParameters;
336 
CryptoJob(Environment * env,v8::Local<v8::Object> object,AsyncWrap::ProviderType type,CryptoJobMode mode,AdditionalParams && params)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 
IsNotIndicativeOfMemoryLeakAtExit()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 
AfterThreadPoolWork(int status)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 
mode()396   CryptoJobMode mode() const { return mode_; }
397 
errors()398   CryptoErrorStore* errors() { return &errors_; }
399 
params()400   AdditionalParams* params() { return &params_; }
401 
MemoryInfoName()402   const char* MemoryInfoName() const override {
403     return CryptoJobTraits::JobName;
404   }
405 
MemoryInfo(MemoryTracker * tracker)406   void MemoryInfo(MemoryTracker* tracker) const override {
407     tracker->TrackField("params", params_);
408     tracker->TrackField("errors", errors_);
409   }
410 
Run(const v8::FunctionCallbackInfo<v8::Value> & args)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 
Initialize(v8::FunctionCallback new_fn,Environment * env,v8::Local<v8::Object> target)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 
RegisterExternalReferences(v8::FunctionCallback new_fn,ExternalReferenceRegistry * registry)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 
456 template <typename DeriveBitsTraits>
457 class DeriveBitsJob final : public CryptoJob<DeriveBitsTraits> {
458  public:
459   using AdditionalParams = typename DeriveBitsTraits::AdditionalParameters;
460 
New(const v8::FunctionCallbackInfo<v8::Value> & args)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 
Initialize(Environment * env,v8::Local<v8::Object> target)478   static void Initialize(
479       Environment* env,
480       v8::Local<v8::Object> target) {
481     CryptoJob<DeriveBitsTraits>::Initialize(New, env, target);
482   }
483 
RegisterExternalReferences(ExternalReferenceRegistry * registry)484   static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
485     CryptoJob<DeriveBitsTraits>::RegisterExternalReferences(New, registry);
486   }
487 
DeriveBitsJob(Environment * env,v8::Local<v8::Object> object,CryptoJobMode mode,AdditionalParams && params)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 
DoThreadPoolWork()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 
ToResult(v8::Local<v8::Value> * err,v8::Local<v8::Value> * result)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 
SET_SELF_SIZE(DeriveBitsJob)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 
546 void ThrowCryptoError(Environment* env,
547                       unsigned long err,  // NOLINT(runtime/int)
548                       const char* message = nullptr);
549 
550 #ifndef OPENSSL_NO_ENGINE
551 struct 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)
engineEnginePointer558     : engine(engine_),
559       finish_on_exit(finish_on_exit_) {}
560 
EnginePointerEnginePointer561   inline EnginePointer(EnginePointer&& other) noexcept
562       : engine(other.engine),
563         finish_on_exit(other.finish_on_exit) {
564     other.release();
565   }
566 
~EnginePointerEnginePointer567   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 
getEnginePointer577   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 
releaseEnginePointer592   inline ENGINE* release() {
593     ENGINE* ret = engine;
594     engine = nullptr;
595     finish_on_exit = false;
596     return ret;
597   }
598 };
599 
600 EnginePointer LoadEngineById(const char* id, CryptoErrorStore* errors);
601 
602 bool SetEngine(
603     const char* id,
604     uint32_t flags,
605     CryptoErrorStore* errors = nullptr);
606 
607 void SetEngine(const v8::FunctionCallbackInfo<v8::Value>& args);
608 #endif  // !OPENSSL_NO_ENGINE
609 
610 void GetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
611 
612 void SetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
613 
614 void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args);
615 
616 class CipherPushContext {
617  public:
CipherPushContext(Environment * env)618   inline explicit CipherPushContext(Environment* env) : env_(env) {}
619 
push_back(const char * str)620   inline void push_back(const char* str) {
621     list_.emplace_back(OneByteString(env_->isolate(), str));
622   }
623 
ToJSArray()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
634 template <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*)>
array_push_back(const TypeName * evp_ref,const char * from,const char * to,void * arg)639 void 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
668 template <class TypeName>
array_push_back(const TypeName * evp_ref,const char * from,const char * to,void * arg)669 void 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 
IsAnyByteSource(v8::Local<v8::Value> arg)679 inline bool IsAnyByteSource(v8::Local<v8::Value> arg) {
680   return arg->IsArrayBufferView() ||
681          arg->IsArrayBuffer() ||
682          arg->IsSharedArrayBuffer();
683 }
684 
685 template <typename T>
686 class ArrayBufferOrViewContents {
687  public:
688   ArrayBufferOrViewContents() = default;
689   ArrayBufferOrViewContents(const ArrayBufferOrViewContents&) = delete;
690   void operator=(const ArrayBufferOrViewContents&) = delete;
691 
ArrayBufferOrViewContents(v8::Local<v8::Value> buf)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 
data()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 
data()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 
size()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.
CheckSizeInt32()738   inline bool CheckSizeInt32() { return size() <= INT_MAX; }
739 
ToByteSource()740   inline ByteSource ToByteSource() const {
741     return ByteSource::Foreign(data(), size());
742   }
743 
ToCopy()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 
ToNullTerminatedCopy()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>
CopyTo(M * dest,size_t len)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 
781 v8::MaybeLocal<v8::Value> EncodeBignum(
782     Environment* env,
783     const BIGNUM* bn,
784     int size,
785     v8::Local<v8::Value>* error);
786 
787 v8::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 
794 bool SetRsaOaepLabel(const EVPKeyCtxPointer& rsa, const ByteSource& label);
795 
796 namespace Util {
797 void Initialize(Environment* env, v8::Local<v8::Object> target);
798 void 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