GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_util.cc Lines: 287 338 84.9 %
Date: 2022-06-15 16:51:59 Branches: 116 236 49.2 %

Line Branch Exec Source
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 {
46
2239
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
2239
  return 1;
61
}
62
63
18430
void CheckEntropy() {
64
  for (;;) {
65
18430
    int status = RAND_status();
66
18430
    CHECK_GE(status, 0);  // Cannot fail.
67
18430
    if (status != 0)
68
18430
      break;
69
70
    // Give up, RAND_poll() not supported.
71
    if (RAND_poll() == 0)
72
      break;
73
  }
74
18430
}
75
76
17479
bool EntropySource(unsigned char* buffer, size_t length) {
77
  // Ensure that OpenSSL's PRNG is properly seeded.
78
17479
  CheckEntropy();
79
  // RAND_bytes() can return 0 to indicate that the entropy data is not truly
80
  // random. That's okay, it's still better than V8's stock source of entropy,
81
  // which is /dev/urandom on UNIX platforms and the current time on Windows.
82
17479
  return RAND_bytes(buffer, length) != -1;
83
}
84
85
111
int PasswordCallback(char* buf, int size, int rwflag, void* u) {
86
111
  const ByteSource* passphrase = *static_cast<const ByteSource**>(u);
87
111
  if (passphrase != nullptr) {
88
91
    size_t buflen = static_cast<size_t>(size);
89
91
    size_t len = passphrase->size();
90
91
    if (buflen < len)
91
2
      return -1;
92
89
    memcpy(buf, passphrase->data(), len);
93
89
    return len;
94
  }
95
96
20
  return -1;
97
}
98
99
// This callback is used to avoid the default passphrase callback in OpenSSL
100
// which will typically prompt for the passphrase. The prompting is designed
101
// for the OpenSSL CLI, but works poorly for Node.js because it involves
102
// synchronous interaction with the controlling terminal, something we never
103
// want, and use this function to avoid it.
104
int NoPasswordCallback(char* buf, int size, int rwflag, void* u) {
105
  return 0;
106
}
107
108
5209
bool ProcessFipsOptions() {
109
  /* Override FIPS settings in configuration file, if needed. */
110

10417
  if (per_process::cli_options->enable_fips_crypto ||
111
5208
      per_process::cli_options->force_fips_crypto) {
112
#if OPENSSL_VERSION_MAJOR >= 3
113
2
    OSSL_PROVIDER* fips_provider = OSSL_PROVIDER_load(nullptr, "fips");
114
2
    if (fips_provider == nullptr)
115
2
      return false;
116
    OSSL_PROVIDER_unload(fips_provider);
117
118
    return EVP_default_properties_enable_fips(nullptr, 1) &&
119
           EVP_default_properties_is_fips_enabled(nullptr);
120
#else
121
    return FIPS_mode() == 0 && FIPS_mode_set(1);
122
#endif
123
  }
124
5207
  return true;
125
}
126
127
6047
bool InitCryptoOnce(Isolate* isolate) {
128
  static uv_once_t init_once = UV_ONCE_INIT;
129
12094
  TryCatch try_catch{isolate};
130
6047
  uv_once(&init_once, InitCryptoOnce);
131

6047
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
132
    try_catch.ReThrow();
133
    return false;
134
  }
135
6047
  return true;
136
}
137
138
// Protect accesses to FIPS state with a mutex. This should potentially
139
// be part of a larger mutex for global OpenSSL state.
140
static Mutex fips_mutex;
141
142
5215
void InitCryptoOnce() {
143
10430
  Mutex::ScopedLock lock(per_process::cli_options_mutex);
144
10430
  Mutex::ScopedLock fips_lock(fips_mutex);
145
#ifndef OPENSSL_IS_BORINGSSL
146
5215
  OPENSSL_INIT_SETTINGS* settings = OPENSSL_INIT_new();
147
148
#if OPENSSL_VERSION_MAJOR < 3
149
  // --openssl-config=...
150
  if (!per_process::cli_options->openssl_config.empty()) {
151
    const char* conf = per_process::cli_options->openssl_config.c_str();
152
    OPENSSL_INIT_set_config_filename(settings, conf);
153
  }
154
#endif
155
156
#if OPENSSL_VERSION_MAJOR >= 3
157
  // --openssl-legacy-provider
158
5215
  if (per_process::cli_options->openssl_legacy_provider) {
159
    OSSL_PROVIDER* legacy_provider = OSSL_PROVIDER_load(nullptr, "legacy");
160
    if (legacy_provider == nullptr) {
161
      fprintf(stderr, "Unable to load legacy provider.\n");
162
    }
163
  }
164
#endif
165
166
5215
  OPENSSL_init_ssl(0, settings);
167
5215
  OPENSSL_INIT_free(settings);
168
5215
  settings = nullptr;
169
170
#ifndef _WIN32
171
5215
  if (per_process::cli_options->secure_heap != 0) {
172

1
    switch (CRYPTO_secure_malloc_init(
173
1
                per_process::cli_options->secure_heap,
174
1
                static_cast<int>(per_process::cli_options->secure_heap_min))) {
175
      case 0:
176
        fprintf(stderr, "Unable to initialize openssl secure heap.\n");
177
        break;
178
      case 2:
179
        // Not a fatal error but worthy of a warning.
180
        fprintf(stderr, "Unable to memory map openssl secure heap.\n");
181
        break;
182
1
      case 1:
183
        // OK!
184
1
        break;
185
    }
186
  }
187
#endif
188
189
#endif  // OPENSSL_IS_BORINGSSL
190
191
  // Turn off compression. Saves memory and protects against CRIME attacks.
192
  // No-op with OPENSSL_NO_COMP builds of OpenSSL.
193
5215
  sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
194
195
#ifndef OPENSSL_NO_ENGINE
196
5215
  ERR_load_ENGINE_strings();
197
5215
  ENGINE_load_builtin_engines();
198
#endif  // !OPENSSL_NO_ENGINE
199
200
5215
  NodeBIO::GetMethod();
201
5215
}
202
203
213
void GetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
204
426
  Mutex::ScopedLock lock(per_process::cli_options_mutex);
205
213
  Mutex::ScopedLock fips_lock(fips_mutex);
206
207
#if OPENSSL_VERSION_MAJOR >= 3
208
426
  args.GetReturnValue().Set(EVP_default_properties_is_fips_enabled(nullptr) ?
209
      1 : 0);
210
#else
211
  args.GetReturnValue().Set(FIPS_mode() ? 1 : 0);
212
#endif
213
213
}
214
215
void SetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
216
  Mutex::ScopedLock lock(per_process::cli_options_mutex);
217
  Mutex::ScopedLock fips_lock(fips_mutex);
218
219
  CHECK(!per_process::cli_options->force_fips_crypto);
220
  Environment* env = Environment::GetCurrent(args);
221
  // TODO(addaleax): This should not be possible to set from worker threads.
222
  // CHECK(env->owns_process_state());
223
  bool enable = args[0]->BooleanValue(env->isolate());
224
225
#if OPENSSL_VERSION_MAJOR >= 3
226
  if (enable == EVP_default_properties_is_fips_enabled(nullptr))
227
#else
228
  if (static_cast<int>(enable) == FIPS_mode())
229
#endif
230
    return;  // No action needed.
231
232
#if OPENSSL_VERSION_MAJOR >= 3
233
  if (!EVP_default_properties_enable_fips(nullptr, enable)) {
234
#else
235
  if (!FIPS_mode_set(enable)) {
236
#endif
237
    unsigned long err = ERR_get_error();  // NOLINT(runtime/int)
238
    return ThrowCryptoError(env, err);
239
  }
240
}
241
242
5
void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args) {
243
10
  Mutex::ScopedLock lock(per_process::cli_options_mutex);
244
5
  Mutex::ScopedLock fips_lock(fips_mutex);
245
246
#ifdef OPENSSL_FIPS
247
#if OPENSSL_VERSION_MAJOR >= 3
248
  OSSL_PROVIDER* fips_provider = nullptr;
249
  if (OSSL_PROVIDER_available(nullptr, "fips")) {
250
    fips_provider = OSSL_PROVIDER_load(nullptr, "fips");
251
  }
252
  const auto enabled = fips_provider == nullptr ? 0 :
253
      OSSL_PROVIDER_self_test(fips_provider) ? 1 : 0;
254
#else
255
  const auto enabled = FIPS_selftest() ? 1 : 0;
256
#endif
257
#else  // OPENSSL_FIPS
258
5
  const auto enabled = 0;
259
#endif  // OPENSSL_FIPS
260
261
10
  args.GetReturnValue().Set(enabled);
262
5
}
263
264
1512
void CryptoErrorStore::Capture() {
265
1512
  errors_.clear();
266
1605
  while (const uint32_t err = ERR_get_error()) {
267
    char buf[256];
268
93
    ERR_error_string_n(err, buf, sizeof(buf));
269
93
    errors_.emplace_back(buf);
270
93
  }
271
1512
  std::reverse(std::begin(errors_), std::end(errors_));
272
1512
}
273
274
6385
bool CryptoErrorStore::Empty() const {
275
6385
  return errors_.empty();
276
}
277
278
210
MaybeLocal<Value> CryptoErrorStore::ToException(
279
    Environment* env,
280
    Local<String> exception_string) const {
281
210
  if (exception_string.IsEmpty()) {
282
106
    CryptoErrorStore copy(*this);
283
53
    if (copy.Empty()) {
284
      // But possibly a bug...
285
      copy.Insert(NodeCryptoError::OK);
286
    }
287
    // Use last element as the error message, everything else goes
288
    // into the .opensslErrorStack property on the exception object.
289
53
    const std::string& last_error_string = copy.errors_.back();
290
    Local<String> exception_string;
291
53
    if (!String::NewFromUtf8(
292
            env->isolate(),
293
            last_error_string.data(),
294
            NewStringType::kNormal,
295
106
            last_error_string.size()).ToLocal(&exception_string)) {
296
      return MaybeLocal<Value>();
297
    }
298
53
    copy.errors_.pop_back();
299
53
    return copy.ToException(env, exception_string);
300
  }
301
302
157
  Local<Value> exception_v = Exception::Error(exception_string);
303
157
  CHECK(!exception_v.IsEmpty());
304
305
157
  if (!Empty()) {
306
26
    CHECK(exception_v->IsObject());
307
26
    Local<Object> exception = exception_v.As<Object>();
308
    Local<Value> stack;
309
78
    if (!ToV8Value(env->context(), errors_).ToLocal(&stack) ||
310
78
        exception->Set(env->context(), env->openssl_error_stack(), stack)
311
26
            .IsNothing()) {
312
      return MaybeLocal<Value>();
313
    }
314
  }
315
316
157
  return exception_v;
317
}
318
319
18205
ByteSource::ByteSource(ByteSource&& other) noexcept
320
18205
    : data_(other.data_),
321
18205
      allocated_data_(other.allocated_data_),
322
36410
      size_(other.size_) {
323
18205
  other.allocated_data_ = nullptr;
324
18205
}
325
326
131114
ByteSource::~ByteSource() {
327
65557
  OPENSSL_clear_free(allocated_data_, size_);
328
65557
}
329
330
14948
ByteSource& ByteSource::operator=(ByteSource&& other) noexcept {
331
14948
  if (&other != this) {
332
14948
    OPENSSL_clear_free(allocated_data_, size_);
333
14948
    data_ = other.data_;
334
14948
    allocated_data_ = other.allocated_data_;
335
14948
    other.allocated_data_ = nullptr;
336
14948
    size_ = other.size_;
337
  }
338
14948
  return *this;
339
}
340
341
2949
std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() {
342
  // It's ok for allocated_data_ to be nullptr but
343
  // only if size_ is zero.
344

2949
  CHECK_IMPLIES(size_ > 0, allocated_data_ != nullptr);
345
  std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore(
346
      allocated_data_,
347
      size(),
348
2944
      [](void* data, size_t length, void* deleter_data) {
349
2944
        OPENSSL_clear_free(deleter_data, length);
350
2949
      }, allocated_data_);
351
2949
  CHECK(ptr);
352
2949
  allocated_data_ = nullptr;
353
2949
  data_ = nullptr;
354
2949
  size_ = 0;
355
2949
  return ptr;
356
}
357
358
2949
Local<ArrayBuffer> ByteSource::ToArrayBuffer(Environment* env) {
359
2949
  std::unique_ptr<BackingStore> store = ReleaseToBackingStore();
360
2949
  return ArrayBuffer::New(env->isolate(), std::move(store));
361
}
362
363
17
MaybeLocal<Uint8Array> ByteSource::ToBuffer(Environment* env) {
364
17
  Local<ArrayBuffer> ab = ToArrayBuffer(env);
365
17
  return Buffer::New(env, ab, 0, ab->ByteLength());
366
}
367
368
505
ByteSource ByteSource::FromBIO(const BIOPointer& bio) {
369
505
  CHECK(bio);
370
  BUF_MEM* bptr;
371
505
  BIO_get_mem_ptr(bio.get(), &bptr);
372
505
  ByteSource::Builder out(bptr->length);
373
505
  memcpy(out.data<void>(), bptr->data, bptr->length);
374
505
  return std::move(out).release();
375
}
376
377
3111
ByteSource ByteSource::FromEncodedString(Environment* env,
378
                                         Local<String> key,
379
                                         enum encoding enc) {
380
3111
  size_t length = 0;
381
3111
  ByteSource out;
382
383

6222
  if (StringBytes::Size(env->isolate(), key, enc).To(&length) && length > 0) {
384
3111
    ByteSource::Builder buf(length);
385
    size_t actual =
386
3111
        StringBytes::Write(env->isolate(), buf.data<char>(), length, key, enc);
387
3111
    out = std::move(buf).release(actual);
388
  }
389
390
3111
  return out;
391
}
392
393
2673
ByteSource ByteSource::FromStringOrBuffer(Environment* env,
394
                                          Local<Value> value) {
395
2673
  return IsAnyByteSource(value) ? FromBuffer(value)
396
2673
                                : FromString(env, value.As<String>());
397
}
398
399
24
ByteSource ByteSource::FromString(Environment* env, Local<String> str,
400
                                  bool ntc) {
401
48
  CHECK(str->IsString());
402
24
  size_t size = str->Utf8Length(env->isolate());
403
24
  size_t alloc_size = ntc ? size + 1 : size;
404
24
  ByteSource::Builder out(alloc_size);
405
24
  int opts = String::NO_OPTIONS;
406
24
  if (!ntc) opts |= String::NO_NULL_TERMINATION;
407
24
  str->WriteUtf8(env->isolate(), out.data<char>(), alloc_size, nullptr, opts);
408
24
  return std::move(out).release();
409
}
410
411
2675
ByteSource ByteSource::FromBuffer(Local<Value> buffer, bool ntc) {
412
5350
  ArrayBufferOrViewContents<char> buf(buffer);
413
2675
  return ntc ? buf.ToNullTerminatedCopy() : buf.ToByteSource();
414
}
415
416
1558
ByteSource ByteSource::FromSecretKeyBytes(
417
    Environment* env,
418
    Local<Value> value) {
419
  // A key can be passed as a string, buffer or KeyObject with type 'secret'.
420
  // If it is a string, we need to convert it to a buffer. We are not doing that
421
  // in JS to avoid creating an unprotected copy on the heap.
422

3116
  return value->IsString() || IsAnyByteSource(value) ?
423
           ByteSource::FromStringOrBuffer(env, value) :
424
1558
           ByteSource::FromSymmetricKeyObjectHandle(value);
425
}
426
427
ByteSource ByteSource::NullTerminatedCopy(Environment* env,
428
                                          Local<Value> value) {
429
  return Buffer::HasInstance(value) ? FromBuffer(value, true)
430
                                    : FromString(env, value.As<String>(), true);
431
}
432
433
14
ByteSource ByteSource::FromSymmetricKeyObjectHandle(Local<Value> handle) {
434
14
  CHECK(handle->IsObject());
435
14
  KeyObjectHandle* key = Unwrap<KeyObjectHandle>(handle.As<Object>());
436
14
  CHECK_NOT_NULL(key);
437
14
  return Foreign(key->Data()->GetSymmetricKey(),
438
28
                 key->Data()->GetSymmetricKeySize());
439
}
440
441
16634
ByteSource ByteSource::Allocated(void* data, size_t size) {
442
16634
  return ByteSource(data, data, size);
443
}
444
445
5093
ByteSource ByteSource::Foreign(const void* data, size_t size) {
446
5093
  return ByteSource(data, nullptr, size);
447
}
448
449
namespace error {
450
104
Maybe<bool> Decorate(Environment* env, Local<Object> obj,
451
              unsigned long err) {  // NOLINT(runtime/int)
452
104
  if (err == 0) return Just(true);  // No decoration necessary.
453
454
93
  const char* ls = ERR_lib_error_string(err);
455
93
  const char* fs = ERR_func_error_string(err);
456
93
  const char* rs = ERR_reason_error_string(err);
457
458
93
  Isolate* isolate = env->isolate();
459
93
  Local<Context> context = isolate->GetCurrentContext();
460
461
93
  if (ls != nullptr) {
462
186
    if (obj->Set(context, env->library_string(),
463
372
                 OneByteString(isolate, ls)).IsNothing()) {
464
1
      return Nothing<bool>();
465
    }
466
  }
467
92
  if (fs != nullptr) {
468
    if (obj->Set(context, env->function_string(),
469
                 OneByteString(isolate, fs)).IsNothing()) {
470
      return Nothing<bool>();
471
    }
472
  }
473
92
  if (rs != nullptr) {
474
184
    if (obj->Set(context, env->reason_string(),
475
368
                 OneByteString(isolate, rs)).IsNothing()) {
476
      return Nothing<bool>();
477
    }
478
479
    // SSL has no API to recover the error name from the number, so we
480
    // transform reason strings like "this error" to "ERR_SSL_THIS_ERROR",
481
    // which ends up being close to the original error macro name.
482
92
    std::string reason(rs);
483
484
1754
    for (auto& c : reason) {
485
1662
      if (c == ' ')
486
183
        c = '_';
487
      else
488
1479
        c = ToUpper(c);
489
    }
490
491
#define OSSL_ERROR_CODES_MAP(V)                                               \
492
    V(SYS)                                                                    \
493
    V(BN)                                                                     \
494
    V(RSA)                                                                    \
495
    V(DH)                                                                     \
496
    V(EVP)                                                                    \
497
    V(BUF)                                                                    \
498
    V(OBJ)                                                                    \
499
    V(PEM)                                                                    \
500
    V(DSA)                                                                    \
501
    V(X509)                                                                   \
502
    V(ASN1)                                                                   \
503
    V(CONF)                                                                   \
504
    V(CRYPTO)                                                                 \
505
    V(EC)                                                                     \
506
    V(SSL)                                                                    \
507
    V(BIO)                                                                    \
508
    V(PKCS7)                                                                  \
509
    V(X509V3)                                                                 \
510
    V(PKCS12)                                                                 \
511
    V(RAND)                                                                   \
512
    V(DSO)                                                                    \
513
    V(ENGINE)                                                                 \
514
    V(OCSP)                                                                   \
515
    V(UI)                                                                     \
516
    V(COMP)                                                                   \
517
    V(ECDSA)                                                                  \
518
    V(ECDH)                                                                   \
519
    V(OSSL_STORE)                                                             \
520
    V(FIPS)                                                                   \
521
    V(CMS)                                                                    \
522
    V(TS)                                                                     \
523
    V(HMAC)                                                                   \
524
    V(CT)                                                                     \
525
    V(ASYNC)                                                                  \
526
    V(KDF)                                                                    \
527
    V(SM2)                                                                    \
528
    V(USER)                                                                   \
529
530
#define V(name) case ERR_LIB_##name: lib = #name "_"; break;
531
92
    const char* lib = "";
532
92
    const char* prefix = "OSSL_";
533









92
    switch (ERR_GET_LIB(err)) { OSSL_ERROR_CODES_MAP(V) }
534
#undef V
535
#undef OSSL_ERROR_CODES_MAP
536
    // Don't generate codes like "ERR_OSSL_SSL_".
537

92
    if (lib && strcmp(lib, "SSL_") == 0)
538
6
      prefix = "";
539
540
    // All OpenSSL reason strings fit in a single 80-column macro definition,
541
    // all prefix lengths are <= 10, and ERR_OSSL_ is 9, so 128 is more than
542
    // sufficient.
543
    char code[128];
544
92
    snprintf(code, sizeof(code), "ERR_%s%s%s", prefix, lib, reason.c_str());
545
546
184
    if (obj->Set(env->isolate()->GetCurrentContext(),
547
             env->code_string(),
548
368
             OneByteString(env->isolate(), code)).IsNothing())
549
      return Nothing<bool>();
550
  }
551
552
92
  return Just(true);
553
}
554
}  // namespace error
555
556
104
void ThrowCryptoError(Environment* env,
557
                      unsigned long err,  // NOLINT(runtime/int)
558
                      // Default, only used if there is no SSL `err` which can
559
                      // be used to create a long-style message string.
560
                      const char* message) {
561
104
  char message_buffer[128] = {0};
562

104
  if (err != 0 || message == nullptr) {
563
93
    ERR_error_string_n(err, message_buffer, sizeof(message_buffer));
564
93
    message = message_buffer;
565
  }
566
104
  HandleScope scope(env->isolate());
567
  Local<String> exception_string;
568
  Local<Value> exception;
569
  Local<Object> obj;
570
208
  if (!String::NewFromUtf8(env->isolate(), message).ToLocal(&exception_string))
571
    return;
572
104
  CryptoErrorStore errors;
573
104
  errors.Capture();
574
104
  if (!errors.ToException(env, exception_string).ToLocal(&exception) ||
575

416
      !exception->ToObject(env->context()).ToLocal(&obj) ||
576

312
      error::Decorate(env, obj, err).IsNothing()) {
577
1
    return;
578
  }
579
103
  env->isolate()->ThrowException(exception);
580
}
581
582
#ifndef OPENSSL_NO_ENGINE
583
11
EnginePointer LoadEngineById(const char* id, CryptoErrorStore* errors) {
584
22
  MarkPopErrorOnReturn mark_pop_error_on_return;
585
586
11
  EnginePointer engine(ENGINE_by_id(id));
587
11
  if (!engine) {
588
    // Engine not found, try loading dynamically.
589
2
    engine = EnginePointer(ENGINE_by_id("dynamic"));
590
2
    if (engine) {
591

4
      if (!ENGINE_ctrl_cmd_string(engine.get(), "SO_PATH", id, 0) ||
592
2
          !ENGINE_ctrl_cmd_string(engine.get(), "LOAD", nullptr, 0)) {
593
2
        engine.reset();
594
      }
595
    }
596
  }
597
598

11
  if (!engine && errors != nullptr) {
599
    errors->Capture();
600
    if (errors->Empty()) {
601
      errors->Insert(NodeCryptoError::ENGINE_NOT_FOUND, id);
602
    }
603
  }
604
605
11
  return engine;
606
}
607
608
11
bool SetEngine(const char* id, uint32_t flags, CryptoErrorStore* errors) {
609
11
  ClearErrorOnReturn clear_error_on_return;
610
22
  EnginePointer engine = LoadEngineById(id, errors);
611
11
  if (!engine)
612
2
    return false;
613
614
9
  if (!ENGINE_set_default(engine.get(), flags)) {
615
    if (errors != nullptr)
616
      errors->Capture();
617
    return false;
618
  }
619
620
9
  return true;
621
}
622
623
11
void SetEngine(const FunctionCallbackInfo<Value>& args) {
624
11
  Environment* env = Environment::GetCurrent(args);
625

33
  CHECK(args.Length() >= 2 && args[0]->IsString());
626
  uint32_t flags;
627
22
  if (!args[1]->Uint32Value(env->context()).To(&flags)) return;
628
629
11
  const node::Utf8Value engine_id(env->isolate(), args[0]);
630
631
22
  args.GetReturnValue().Set(SetEngine(*engine_id, flags));
632
}
633
#endif  // !OPENSSL_NO_ENGINE
634
635
2593
MaybeLocal<Value> EncodeBignum(
636
    Environment* env,
637
    const BIGNUM* bn,
638
    int size,
639
    Local<Value>* error) {
640
5186
  std::vector<uint8_t> buf(size);
641
2593
  CHECK_EQ(BN_bn2binpad(bn, buf.data(), size), size);
642
  return StringBytes::Encode(
643
      env->isolate(),
644
2593
      reinterpret_cast<const char*>(buf.data()),
645
      buf.size(),
646
      BASE64URL,
647
5186
      error);
648
}
649
650
2593
Maybe<bool> SetEncodedValue(
651
    Environment* env,
652
    Local<Object> target,
653
    Local<String> name,
654
    const BIGNUM* bn,
655
    int size) {
656
  Local<Value> value;
657
  Local<Value> error;
658
2593
  CHECK_NOT_NULL(bn);
659
2593
  if (size == 0)
660
2084
    size = BN_num_bytes(bn);
661
5186
  if (!EncodeBignum(env, bn, size, &error).ToLocal(&value)) {
662
    if (!error.IsEmpty())
663
      env->isolate()->ThrowException(error);
664
    return Nothing<bool>();
665
  }
666
2593
  return target->Set(env->context(), name, value);
667
}
668
669
5266
CryptoJobMode GetCryptoJobMode(v8::Local<v8::Value> args) {
670
5266
  CHECK(args->IsUint32());
671
5266
  uint32_t mode = args.As<v8::Uint32>()->Value();
672
5266
  CHECK_LE(mode, kCryptoJobSync);
673
5266
  return static_cast<CryptoJobMode>(mode);
674
}
675
676
namespace {
677
// SecureBuffer uses openssl to allocate a Uint8Array using
678
// OPENSSL_secure_malloc. Because we do not yet actually
679
// make use of secure heap, this has the same semantics as
680
// using OPENSSL_malloc. However, if the secure heap is
681
// initialized, SecureBuffer will automatically use it.
682
4
void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
683
4
  CHECK(args[0]->IsUint32());
684
4
  Environment* env = Environment::GetCurrent(args);
685
8
  uint32_t len = args[0].As<Uint32>()->Value();
686
4
  char* data = static_cast<char*>(OPENSSL_secure_malloc(len));
687
4
  if (data == nullptr) {
688
    // There's no memory available for the allocation.
689
    // Return nothing.
690
    return;
691
  }
692
4
  memset(data, 0, len);
693
  std::shared_ptr<BackingStore> store =
694
4
      ArrayBuffer::NewBackingStore(
695
          data,
696
          len,
697
4
          [](void* data, size_t len, void* deleter_data) {
698
4
            OPENSSL_secure_clear_free(data, len);
699
4
          },
700
4
          data);
701
4
  Local<ArrayBuffer> buffer = ArrayBuffer::New(env->isolate(), store);
702
8
  args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len));
703
}
704
705
4
void SecureHeapUsed(const FunctionCallbackInfo<Value>& args) {
706
4
  Environment* env = Environment::GetCurrent(args);
707
4
  if (CRYPTO_secure_malloc_initialized())
708
8
    args.GetReturnValue().Set(
709
4
        BigInt::New(env->isolate(), CRYPTO_secure_used()));
710
4
}
711
}  // namespace
712
713
namespace Util {
714
848
void Initialize(Environment* env, Local<Object> target) {
715
#ifndef OPENSSL_NO_ENGINE
716
848
  env->SetMethod(target, "setEngine", SetEngine);
717
#endif  // !OPENSSL_NO_ENGINE
718
719
848
  env->SetMethodNoSideEffect(target, "getFipsCrypto", GetFipsCrypto);
720
848
  env->SetMethod(target, "setFipsCrypto", SetFipsCrypto);
721
848
  env->SetMethodNoSideEffect(target, "testFipsCrypto", TestFipsCrypto);
722
723
2544
  NODE_DEFINE_CONSTANT(target, kCryptoJobAsync);
724
1696
  NODE_DEFINE_CONSTANT(target, kCryptoJobSync);
725
726
848
  env->SetMethod(target, "secureBuffer", SecureBuffer);
727
848
  env->SetMethod(target, "secureHeapUsed", SecureHeapUsed);
728
848
}
729
5205
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
730
#ifndef OPENSSL_NO_ENGINE
731
5205
  registry->Register(SetEngine);
732
#endif  // !OPENSSL_NO_ENGINE
733
734
5205
  registry->Register(GetFipsCrypto);
735
5205
  registry->Register(SetFipsCrypto);
736
5205
  registry->Register(TestFipsCrypto);
737
5205
  registry->Register(SecureBuffer);
738
5205
  registry->Register(SecureHeapUsed);
739
5205
}
740
741
}  // namespace Util
742
743
}  // namespace crypto
744
}  // namespace node