1 #include "crypto/crypto_util.h"
2 #include "async_wrap-inl.h"
3 #include "crypto/crypto_bio.h"
4 #include "crypto/crypto_keys.h"
5 #include "env-inl.h"
6 #include "memory_tracker-inl.h"
7 #include "node_buffer.h"
8 #include "node_options-inl.h"
9 #include "string_bytes.h"
10 #include "threadpoolwork-inl.h"
11 #include "util-inl.h"
12 #include "v8.h"
13
14 #include "math.h"
15
16 #if OPENSSL_VERSION_MAJOR >= 3
17 #include "openssl/provider.h"
18 #endif
19
20 #include <openssl/rand.h>
21
22 namespace node {
23
24 using v8::ArrayBuffer;
25 using v8::BackingStore;
26 using v8::BigInt;
27 using v8::Context;
28 using v8::Exception;
29 using v8::FunctionCallbackInfo;
30 using v8::HandleScope;
31 using v8::Isolate;
32 using v8::Just;
33 using v8::Local;
34 using v8::Maybe;
35 using v8::MaybeLocal;
36 using v8::NewStringType;
37 using v8::Nothing;
38 using v8::Object;
39 using v8::String;
40 using v8::TryCatch;
41 using v8::Uint32;
42 using v8::Uint8Array;
43 using v8::Value;
44
45 namespace crypto {
VerifyCallback(int preverify_ok,X509_STORE_CTX * ctx)46 int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) {
47 // From https://www.openssl.org/docs/man1.1.1/man3/SSL_verify_cb:
48 //
49 // If VerifyCallback returns 1, the verification process is continued. If
50 // VerifyCallback always returns 1, the TLS/SSL handshake will not be
51 // terminated with respect to verification failures and the connection will
52 // be established. The calling process can however retrieve the error code
53 // of the last verification error using SSL_get_verify_result(3) or by
54 // maintaining its own error storage managed by VerifyCallback.
55 //
56 // Since we cannot perform I/O quickly enough with X509_STORE_CTX_ APIs in
57 // this callback, we ignore all preverify_ok errors and let the handshake
58 // continue. It is imperative that the user use Connection::VerifyError after
59 // the 'secure' callback has been made.
60 return 1;
61 }
62
CSPRNG(void * buffer,size_t length)63 MUST_USE_RESULT CSPRNGResult CSPRNG(void* buffer, size_t length) {
64 unsigned char* buf = static_cast<unsigned char*>(buffer);
65 do {
66 if (1 == RAND_status()) {
67 #if OPENSSL_VERSION_MAJOR >= 3
68 if (1 == RAND_bytes_ex(nullptr, buf, length, 0)) return {true};
69 #else
70 while (length > INT_MAX && 1 == RAND_bytes(buf, INT_MAX)) {
71 buf += INT_MAX;
72 length -= INT_MAX;
73 }
74 if (length <= INT_MAX && 1 == RAND_bytes(buf, static_cast<int>(length)))
75 return {true};
76 #endif
77 }
78 #if OPENSSL_VERSION_MAJOR >= 3
79 const auto code = ERR_peek_last_error();
80 // A misconfigured OpenSSL 3 installation may report 1 from RAND_poll()
81 // and RAND_status() but fail in RAND_bytes() if it cannot look up
82 // a matching algorithm for the CSPRNG.
83 if (ERR_GET_LIB(code) == ERR_LIB_RAND) {
84 const auto reason = ERR_GET_REASON(code);
85 if (reason == RAND_R_ERROR_INSTANTIATING_DRBG ||
86 reason == RAND_R_UNABLE_TO_FETCH_DRBG ||
87 reason == RAND_R_UNABLE_TO_CREATE_DRBG) {
88 return {false};
89 }
90 }
91 #endif
92 } while (1 == RAND_poll());
93
94 return {false};
95 }
96
PasswordCallback(char * buf,int size,int rwflag,void * u)97 int PasswordCallback(char* buf, int size, int rwflag, void* u) {
98 const ByteSource* passphrase = *static_cast<const ByteSource**>(u);
99 if (passphrase != nullptr) {
100 size_t buflen = static_cast<size_t>(size);
101 size_t len = passphrase->size();
102 if (buflen < len)
103 return -1;
104 memcpy(buf, passphrase->data(), len);
105 return len;
106 }
107
108 return -1;
109 }
110
111 // This callback is used to avoid the default passphrase callback in OpenSSL
112 // which will typically prompt for the passphrase. The prompting is designed
113 // for the OpenSSL CLI, but works poorly for Node.js because it involves
114 // synchronous interaction with the controlling terminal, something we never
115 // want, and use this function to avoid it.
NoPasswordCallback(char * buf,int size,int rwflag,void * u)116 int NoPasswordCallback(char* buf, int size, int rwflag, void* u) {
117 return 0;
118 }
119
ProcessFipsOptions()120 bool ProcessFipsOptions() {
121 /* Override FIPS settings in configuration file, if needed. */
122 if (per_process::cli_options->enable_fips_crypto ||
123 per_process::cli_options->force_fips_crypto) {
124 #if OPENSSL_VERSION_MAJOR >= 3
125 OSSL_PROVIDER* fips_provider = OSSL_PROVIDER_load(nullptr, "fips");
126 if (fips_provider == nullptr)
127 return false;
128 OSSL_PROVIDER_unload(fips_provider);
129
130 return EVP_default_properties_enable_fips(nullptr, 1) &&
131 EVP_default_properties_is_fips_enabled(nullptr);
132 #else
133 if (FIPS_mode() == 0) return FIPS_mode_set(1);
134
135 #endif
136 }
137 return true;
138 }
139
InitCryptoOnce(Isolate * isolate)140 bool InitCryptoOnce(Isolate* isolate) {
141 static uv_once_t init_once = UV_ONCE_INIT;
142 TryCatch try_catch{isolate};
143 uv_once(&init_once, InitCryptoOnce);
144 if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
145 try_catch.ReThrow();
146 return false;
147 }
148 return true;
149 }
150
151 // Protect accesses to FIPS state with a mutex. This should potentially
152 // be part of a larger mutex for global OpenSSL state.
153 static Mutex fips_mutex;
154
InitCryptoOnce()155 void InitCryptoOnce() {
156 Mutex::ScopedLock lock(per_process::cli_options_mutex);
157 Mutex::ScopedLock fips_lock(fips_mutex);
158 #ifndef OPENSSL_IS_BORINGSSL
159 OPENSSL_INIT_SETTINGS* settings = OPENSSL_INIT_new();
160
161 #if OPENSSL_VERSION_MAJOR < 3
162 // --openssl-config=...
163 if (!per_process::cli_options->openssl_config.empty()) {
164 const char* conf = per_process::cli_options->openssl_config.c_str();
165 OPENSSL_INIT_set_config_filename(settings, conf);
166 }
167 #endif
168
169 #if OPENSSL_VERSION_MAJOR >= 3
170 // --openssl-legacy-provider
171 if (per_process::cli_options->openssl_legacy_provider) {
172 OSSL_PROVIDER* legacy_provider = OSSL_PROVIDER_load(nullptr, "legacy");
173 if (legacy_provider == nullptr) {
174 fprintf(stderr, "Unable to load legacy provider.\n");
175 }
176 }
177 #endif
178
179 OPENSSL_init_ssl(0, settings);
180 OPENSSL_INIT_free(settings);
181 settings = nullptr;
182
183 #ifndef _WIN32
184 if (per_process::cli_options->secure_heap != 0) {
185 switch (CRYPTO_secure_malloc_init(
186 per_process::cli_options->secure_heap,
187 static_cast<int>(per_process::cli_options->secure_heap_min))) {
188 case 0:
189 fprintf(stderr, "Unable to initialize openssl secure heap.\n");
190 break;
191 case 2:
192 // Not a fatal error but worthy of a warning.
193 fprintf(stderr, "Unable to memory map openssl secure heap.\n");
194 break;
195 case 1:
196 // OK!
197 break;
198 }
199 }
200 #endif
201
202 #endif // OPENSSL_IS_BORINGSSL
203
204 // Turn off compression. Saves memory and protects against CRIME attacks.
205 // No-op with OPENSSL_NO_COMP builds of OpenSSL.
206 sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
207
208 #ifndef OPENSSL_NO_ENGINE
209 ERR_load_ENGINE_strings();
210 ENGINE_load_builtin_engines();
211 #endif // !OPENSSL_NO_ENGINE
212 }
213
GetFipsCrypto(const FunctionCallbackInfo<Value> & args)214 void GetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
215 Mutex::ScopedLock lock(per_process::cli_options_mutex);
216 Mutex::ScopedLock fips_lock(fips_mutex);
217
218 #if OPENSSL_VERSION_MAJOR >= 3
219 args.GetReturnValue().Set(EVP_default_properties_is_fips_enabled(nullptr) ?
220 1 : 0);
221 #else
222 args.GetReturnValue().Set(FIPS_mode() ? 1 : 0);
223 #endif
224 }
225
SetFipsCrypto(const FunctionCallbackInfo<Value> & args)226 void SetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
227 Mutex::ScopedLock lock(per_process::cli_options_mutex);
228 Mutex::ScopedLock fips_lock(fips_mutex);
229
230 CHECK(!per_process::cli_options->force_fips_crypto);
231 Environment* env = Environment::GetCurrent(args);
232 // TODO(addaleax): This should not be possible to set from worker threads.
233 // CHECK(env->owns_process_state());
234 bool enable = args[0]->BooleanValue(env->isolate());
235
236 #if OPENSSL_VERSION_MAJOR >= 3
237 if (enable == EVP_default_properties_is_fips_enabled(nullptr))
238 #else
239 if (static_cast<int>(enable) == FIPS_mode())
240 #endif
241 return; // No action needed.
242
243 #if OPENSSL_VERSION_MAJOR >= 3
244 if (!EVP_default_properties_enable_fips(nullptr, enable)) {
245 #else
246 if (!FIPS_mode_set(enable)) {
247 #endif
248 unsigned long err = ERR_get_error(); // NOLINT(runtime/int)
249 return ThrowCryptoError(env, err);
250 }
251 }
252
253 void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args) {
254 Mutex::ScopedLock lock(per_process::cli_options_mutex);
255 Mutex::ScopedLock fips_lock(fips_mutex);
256
257 #if OPENSSL_VERSION_MAJOR >= 3
258 OSSL_PROVIDER* fips_provider = nullptr;
259 if (OSSL_PROVIDER_available(nullptr, "fips")) {
260 fips_provider = OSSL_PROVIDER_load(nullptr, "fips");
261 }
262 const auto enabled = fips_provider == nullptr ? 0 :
263 OSSL_PROVIDER_self_test(fips_provider) ? 1 : 0;
264 #else
265 #ifdef OPENSSL_FIPS
266 const auto enabled = FIPS_selftest() ? 1 : 0;
267 #else // OPENSSL_FIPS
268 const auto enabled = 0;
269 #endif // OPENSSL_FIPS
270 #endif
271
272 args.GetReturnValue().Set(enabled);
273 }
274
275 void CryptoErrorStore::Capture() {
276 errors_.clear();
277 while (const uint32_t err = ERR_get_error()) {
278 char buf[256];
279 ERR_error_string_n(err, buf, sizeof(buf));
280 errors_.emplace_back(buf);
281 }
282 std::reverse(std::begin(errors_), std::end(errors_));
283 }
284
285 bool CryptoErrorStore::Empty() const {
286 return errors_.empty();
287 }
288
289 MaybeLocal<Value> CryptoErrorStore::ToException(
290 Environment* env,
291 Local<String> exception_string) const {
292 if (exception_string.IsEmpty()) {
293 CryptoErrorStore copy(*this);
294 if (copy.Empty()) {
295 // But possibly a bug...
296 copy.Insert(NodeCryptoError::OK);
297 }
298 // Use last element as the error message, everything else goes
299 // into the .opensslErrorStack property on the exception object.
300 const std::string& last_error_string = copy.errors_.back();
301 Local<String> exception_string;
302 if (!String::NewFromUtf8(
303 env->isolate(),
304 last_error_string.data(),
305 NewStringType::kNormal,
306 last_error_string.size()).ToLocal(&exception_string)) {
307 return MaybeLocal<Value>();
308 }
309 copy.errors_.pop_back();
310 return copy.ToException(env, exception_string);
311 }
312
313 Local<Value> exception_v = Exception::Error(exception_string);
314 CHECK(!exception_v.IsEmpty());
315
316 if (!Empty()) {
317 CHECK(exception_v->IsObject());
318 Local<Object> exception = exception_v.As<Object>();
319 Local<Value> stack;
320 if (!ToV8Value(env->context(), errors_).ToLocal(&stack) ||
321 exception->Set(env->context(), env->openssl_error_stack(), stack)
322 .IsNothing()) {
323 return MaybeLocal<Value>();
324 }
325 }
326
327 return exception_v;
328 }
329
330 ByteSource::ByteSource(ByteSource&& other) noexcept
331 : data_(other.data_),
332 allocated_data_(other.allocated_data_),
333 size_(other.size_) {
334 other.allocated_data_ = nullptr;
335 }
336
337 ByteSource::~ByteSource() {
338 OPENSSL_clear_free(allocated_data_, size_);
339 }
340
341 ByteSource& ByteSource::operator=(ByteSource&& other) noexcept {
342 if (&other != this) {
343 OPENSSL_clear_free(allocated_data_, size_);
344 data_ = other.data_;
345 allocated_data_ = other.allocated_data_;
346 other.allocated_data_ = nullptr;
347 size_ = other.size_;
348 }
349 return *this;
350 }
351
352 std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() {
353 // It's ok for allocated_data_ to be nullptr but
354 // only if size_ is zero.
355 CHECK_IMPLIES(size_ > 0, allocated_data_ != nullptr);
356 std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore(
357 allocated_data_,
358 size(),
359 [](void* data, size_t length, void* deleter_data) {
360 OPENSSL_clear_free(deleter_data, length);
361 }, allocated_data_);
362 CHECK(ptr);
363 allocated_data_ = nullptr;
364 data_ = nullptr;
365 size_ = 0;
366 return ptr;
367 }
368
369 Local<ArrayBuffer> ByteSource::ToArrayBuffer(Environment* env) {
370 std::unique_ptr<BackingStore> store = ReleaseToBackingStore();
371 return ArrayBuffer::New(env->isolate(), std::move(store));
372 }
373
374 MaybeLocal<Uint8Array> ByteSource::ToBuffer(Environment* env) {
375 Local<ArrayBuffer> ab = ToArrayBuffer(env);
376 return Buffer::New(env, ab, 0, ab->ByteLength());
377 }
378
379 ByteSource ByteSource::FromBIO(const BIOPointer& bio) {
380 CHECK(bio);
381 BUF_MEM* bptr;
382 BIO_get_mem_ptr(bio.get(), &bptr);
383 ByteSource::Builder out(bptr->length);
384 memcpy(out.data<void>(), bptr->data, bptr->length);
385 return std::move(out).release();
386 }
387
388 ByteSource ByteSource::FromEncodedString(Environment* env,
389 Local<String> key,
390 enum encoding enc) {
391 size_t length = 0;
392 ByteSource out;
393
394 if (StringBytes::Size(env->isolate(), key, enc).To(&length) && length > 0) {
395 ByteSource::Builder buf(length);
396 size_t actual =
397 StringBytes::Write(env->isolate(), buf.data<char>(), length, key, enc);
398 out = std::move(buf).release(actual);
399 }
400
401 return out;
402 }
403
404 ByteSource ByteSource::FromStringOrBuffer(Environment* env,
405 Local<Value> value) {
406 return IsAnyByteSource(value) ? FromBuffer(value)
407 : FromString(env, value.As<String>());
408 }
409
410 ByteSource ByteSource::FromString(Environment* env, Local<String> str,
411 bool ntc) {
412 CHECK(str->IsString());
413 size_t size = str->Utf8Length(env->isolate());
414 size_t alloc_size = ntc ? size + 1 : size;
415 ByteSource::Builder out(alloc_size);
416 int opts = String::NO_OPTIONS;
417 if (!ntc) opts |= String::NO_NULL_TERMINATION;
418 str->WriteUtf8(env->isolate(), out.data<char>(), alloc_size, nullptr, opts);
419 return std::move(out).release();
420 }
421
422 ByteSource ByteSource::FromBuffer(Local<Value> buffer, bool ntc) {
423 ArrayBufferOrViewContents<char> buf(buffer);
424 return ntc ? buf.ToNullTerminatedCopy() : buf.ToByteSource();
425 }
426
427 ByteSource ByteSource::FromSecretKeyBytes(
428 Environment* env,
429 Local<Value> value) {
430 // A key can be passed as a string, buffer or KeyObject with type 'secret'.
431 // If it is a string, we need to convert it to a buffer. We are not doing that
432 // in JS to avoid creating an unprotected copy on the heap.
433 return value->IsString() || IsAnyByteSource(value) ?
434 ByteSource::FromStringOrBuffer(env, value) :
435 ByteSource::FromSymmetricKeyObjectHandle(value);
436 }
437
438 ByteSource ByteSource::NullTerminatedCopy(Environment* env,
439 Local<Value> value) {
440 return Buffer::HasInstance(value) ? FromBuffer(value, true)
441 : FromString(env, value.As<String>(), true);
442 }
443
444 ByteSource ByteSource::FromSymmetricKeyObjectHandle(Local<Value> handle) {
445 CHECK(handle->IsObject());
446 KeyObjectHandle* key = Unwrap<KeyObjectHandle>(handle.As<Object>());
447 CHECK_NOT_NULL(key);
448 return Foreign(key->Data()->GetSymmetricKey(),
449 key->Data()->GetSymmetricKeySize());
450 }
451
452 ByteSource ByteSource::Allocated(void* data, size_t size) {
453 return ByteSource(data, data, size);
454 }
455
456 ByteSource ByteSource::Foreign(const void* data, size_t size) {
457 return ByteSource(data, nullptr, size);
458 }
459
460 namespace error {
461 Maybe<bool> Decorate(Environment* env, Local<Object> obj,
462 unsigned long err) { // NOLINT(runtime/int)
463 if (err == 0) return Just(true); // No decoration necessary.
464
465 const char* ls = ERR_lib_error_string(err);
466 const char* fs = ERR_func_error_string(err);
467 const char* rs = ERR_reason_error_string(err);
468
469 Isolate* isolate = env->isolate();
470 Local<Context> context = isolate->GetCurrentContext();
471
472 if (ls != nullptr) {
473 if (obj->Set(context, env->library_string(),
474 OneByteString(isolate, ls)).IsNothing()) {
475 return Nothing<bool>();
476 }
477 }
478 if (fs != nullptr) {
479 if (obj->Set(context, env->function_string(),
480 OneByteString(isolate, fs)).IsNothing()) {
481 return Nothing<bool>();
482 }
483 }
484 if (rs != nullptr) {
485 if (obj->Set(context, env->reason_string(),
486 OneByteString(isolate, rs)).IsNothing()) {
487 return Nothing<bool>();
488 }
489
490 // SSL has no API to recover the error name from the number, so we
491 // transform reason strings like "this error" to "ERR_SSL_THIS_ERROR",
492 // which ends up being close to the original error macro name.
493 std::string reason(rs);
494
495 for (auto& c : reason) {
496 if (c == ' ')
497 c = '_';
498 else
499 c = ToUpper(c);
500 }
501
502 #define OSSL_ERROR_CODES_MAP(V) \
503 V(SYS) \
504 V(BN) \
505 V(RSA) \
506 V(DH) \
507 V(EVP) \
508 V(BUF) \
509 V(OBJ) \
510 V(PEM) \
511 V(DSA) \
512 V(X509) \
513 V(ASN1) \
514 V(CONF) \
515 V(CRYPTO) \
516 V(EC) \
517 V(SSL) \
518 V(BIO) \
519 V(PKCS7) \
520 V(X509V3) \
521 V(PKCS12) \
522 V(RAND) \
523 V(DSO) \
524 V(ENGINE) \
525 V(OCSP) \
526 V(UI) \
527 V(COMP) \
528 V(ECDSA) \
529 V(ECDH) \
530 V(OSSL_STORE) \
531 V(FIPS) \
532 V(CMS) \
533 V(TS) \
534 V(HMAC) \
535 V(CT) \
536 V(ASYNC) \
537 V(KDF) \
538 V(SM2) \
539 V(USER) \
540
541 #define V(name) case ERR_LIB_##name: lib = #name "_"; break;
542 const char* lib = "";
543 const char* prefix = "OSSL_";
544 switch (ERR_GET_LIB(err)) { OSSL_ERROR_CODES_MAP(V) }
545 #undef V
546 #undef OSSL_ERROR_CODES_MAP
547 // Don't generate codes like "ERR_OSSL_SSL_".
548 if (lib && strcmp(lib, "SSL_") == 0)
549 prefix = "";
550
551 // All OpenSSL reason strings fit in a single 80-column macro definition,
552 // all prefix lengths are <= 10, and ERR_OSSL_ is 9, so 128 is more than
553 // sufficient.
554 char code[128];
555 snprintf(code, sizeof(code), "ERR_%s%s%s", prefix, lib, reason.c_str());
556
557 if (obj->Set(env->isolate()->GetCurrentContext(),
558 env->code_string(),
559 OneByteString(env->isolate(), code)).IsNothing())
560 return Nothing<bool>();
561 }
562
563 return Just(true);
564 }
565 } // namespace error
566
567 void ThrowCryptoError(Environment* env,
568 unsigned long err, // NOLINT(runtime/int)
569 // Default, only used if there is no SSL `err` which can
570 // be used to create a long-style message string.
571 const char* message) {
572 char message_buffer[128] = {0};
573 if (err != 0 || message == nullptr) {
574 ERR_error_string_n(err, message_buffer, sizeof(message_buffer));
575 message = message_buffer;
576 }
577 HandleScope scope(env->isolate());
578 Local<String> exception_string;
579 Local<Value> exception;
580 Local<Object> obj;
581 if (!String::NewFromUtf8(env->isolate(), message).ToLocal(&exception_string))
582 return;
583 CryptoErrorStore errors;
584 errors.Capture();
585 if (!errors.ToException(env, exception_string).ToLocal(&exception) ||
586 !exception->ToObject(env->context()).ToLocal(&obj) ||
587 error::Decorate(env, obj, err).IsNothing()) {
588 return;
589 }
590 env->isolate()->ThrowException(exception);
591 }
592
593 #ifndef OPENSSL_NO_ENGINE
594 EnginePointer LoadEngineById(const char* id, CryptoErrorStore* errors) {
595 MarkPopErrorOnReturn mark_pop_error_on_return;
596
597 EnginePointer engine(ENGINE_by_id(id));
598 if (!engine) {
599 // Engine not found, try loading dynamically.
600 engine = EnginePointer(ENGINE_by_id("dynamic"));
601 if (engine) {
602 if (!ENGINE_ctrl_cmd_string(engine.get(), "SO_PATH", id, 0) ||
603 !ENGINE_ctrl_cmd_string(engine.get(), "LOAD", nullptr, 0)) {
604 engine.reset();
605 }
606 }
607 }
608
609 if (!engine && errors != nullptr) {
610 errors->Capture();
611 if (errors->Empty()) {
612 errors->Insert(NodeCryptoError::ENGINE_NOT_FOUND, id);
613 }
614 }
615
616 return engine;
617 }
618
619 bool SetEngine(const char* id, uint32_t flags, CryptoErrorStore* errors) {
620 ClearErrorOnReturn clear_error_on_return;
621 EnginePointer engine = LoadEngineById(id, errors);
622 if (!engine)
623 return false;
624
625 if (!ENGINE_set_default(engine.get(), flags)) {
626 if (errors != nullptr)
627 errors->Capture();
628 return false;
629 }
630
631 return true;
632 }
633
634 void SetEngine(const FunctionCallbackInfo<Value>& args) {
635 Environment* env = Environment::GetCurrent(args);
636 CHECK(args.Length() >= 2 && args[0]->IsString());
637 uint32_t flags;
638 if (!args[1]->Uint32Value(env->context()).To(&flags)) return;
639
640 const node::Utf8Value engine_id(env->isolate(), args[0]);
641
642 args.GetReturnValue().Set(SetEngine(*engine_id, flags));
643 }
644 #endif // !OPENSSL_NO_ENGINE
645
646 MaybeLocal<Value> EncodeBignum(
647 Environment* env,
648 const BIGNUM* bn,
649 int size,
650 Local<Value>* error) {
651 std::vector<uint8_t> buf(size);
652 CHECK_EQ(BN_bn2binpad(bn, buf.data(), size), size);
653 return StringBytes::Encode(
654 env->isolate(),
655 reinterpret_cast<const char*>(buf.data()),
656 buf.size(),
657 BASE64URL,
658 error);
659 }
660
661 Maybe<bool> SetEncodedValue(
662 Environment* env,
663 Local<Object> target,
664 Local<String> name,
665 const BIGNUM* bn,
666 int size) {
667 Local<Value> value;
668 Local<Value> error;
669 CHECK_NOT_NULL(bn);
670 if (size == 0)
671 size = BN_num_bytes(bn);
672 if (!EncodeBignum(env, bn, size, &error).ToLocal(&value)) {
673 if (!error.IsEmpty())
674 env->isolate()->ThrowException(error);
675 return Nothing<bool>();
676 }
677 return target->Set(env->context(), name, value);
678 }
679
680 bool SetRsaOaepLabel(const EVPKeyCtxPointer& ctx, const ByteSource& label) {
681 if (label.size() != 0) {
682 // OpenSSL takes ownership of the label, so we need to create a copy.
683 void* label_copy = OPENSSL_memdup(label.data(), label.size());
684 CHECK_NOT_NULL(label_copy);
685 int ret = EVP_PKEY_CTX_set0_rsa_oaep_label(
686 ctx.get(), static_cast<unsigned char*>(label_copy), label.size());
687 if (ret <= 0) {
688 OPENSSL_free(label_copy);
689 return false;
690 }
691 }
692 return true;
693 }
694
695 CryptoJobMode GetCryptoJobMode(v8::Local<v8::Value> args) {
696 CHECK(args->IsUint32());
697 uint32_t mode = args.As<v8::Uint32>()->Value();
698 CHECK_LE(mode, kCryptoJobSync);
699 return static_cast<CryptoJobMode>(mode);
700 }
701
702 namespace {
703 // SecureBuffer uses OPENSSL_secure_malloc to allocate a Uint8Array.
704 // Without --secure-heap, OpenSSL's secure heap is disabled,
705 // in which case this has the same semantics as
706 // using OPENSSL_malloc. However, if the secure heap is
707 // initialized, SecureBuffer will automatically use it.
708 void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
709 CHECK(args[0]->IsUint32());
710 Environment* env = Environment::GetCurrent(args);
711 uint32_t len = args[0].As<Uint32>()->Value();
712 void* data = OPENSSL_secure_zalloc(len);
713 if (data == nullptr) {
714 // There's no memory available for the allocation.
715 // Return nothing.
716 return;
717 }
718 std::shared_ptr<BackingStore> store =
719 ArrayBuffer::NewBackingStore(
720 data,
721 len,
722 [](void* data, size_t len, void* deleter_data) {
723 OPENSSL_secure_clear_free(data, len);
724 },
725 data);
726 Local<ArrayBuffer> buffer = ArrayBuffer::New(env->isolate(), store);
727 args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len));
728 }
729
730 void SecureHeapUsed(const FunctionCallbackInfo<Value>& args) {
731 Environment* env = Environment::GetCurrent(args);
732 if (CRYPTO_secure_malloc_initialized())
733 args.GetReturnValue().Set(
734 BigInt::New(env->isolate(), CRYPTO_secure_used()));
735 }
736 } // namespace
737
738 namespace Util {
739 void Initialize(Environment* env, Local<Object> target) {
740 Local<Context> context = env->context();
741 #ifndef OPENSSL_NO_ENGINE
742 SetMethod(context, target, "setEngine", SetEngine);
743 #endif // !OPENSSL_NO_ENGINE
744
745 SetMethodNoSideEffect(context, target, "getFipsCrypto", GetFipsCrypto);
746 SetMethod(context, target, "setFipsCrypto", SetFipsCrypto);
747 SetMethodNoSideEffect(context, target, "testFipsCrypto", TestFipsCrypto);
748
749 NODE_DEFINE_CONSTANT(target, kCryptoJobAsync);
750 NODE_DEFINE_CONSTANT(target, kCryptoJobSync);
751
752 SetMethod(context, target, "secureBuffer", SecureBuffer);
753 SetMethod(context, target, "secureHeapUsed", SecureHeapUsed);
754 }
755 void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
756 #ifndef OPENSSL_NO_ENGINE
757 registry->Register(SetEngine);
758 #endif // !OPENSSL_NO_ENGINE
759
760 registry->Register(GetFipsCrypto);
761 registry->Register(SetFipsCrypto);
762 registry->Register(TestFipsCrypto);
763 registry->Register(SecureBuffer);
764 registry->Register(SecureHeapUsed);
765 }
766
767 } // namespace Util
768
769 } // namespace crypto
770 } // namespace node
771