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 ¶ms_; }
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, ¶ms)
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