GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 |
2237 |
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 |
2237 |
return 1; |
|
61 |
} |
||
62 |
|||
63 |
18372 |
void CheckEntropy() { |
|
64 |
for (;;) { |
||
65 |
18372 |
int status = RAND_status(); |
|
66 |
✗✓ | 18372 |
CHECK_GE(status, 0); // Cannot fail. |
67 |
✓✗ | 18372 |
if (status != 0) |
68 |
18372 |
break; |
|
69 |
|||
70 |
// Give up, RAND_poll() not supported. |
||
71 |
if (RAND_poll() == 0) |
||
72 |
break; |
||
73 |
} |
||
74 |
18372 |
} |
|
75 |
|||
76 |
17432 |
bool EntropySource(unsigned char* buffer, size_t length) { |
|
77 |
// Ensure that OpenSSL's PRNG is properly seeded. |
||
78 |
17432 |
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 |
17432 |
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->get(), 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 |
5188 |
bool ProcessFipsOptions() { |
|
109 |
/* Override FIPS settings in configuration file, if needed. */ |
||
110 |
✓✓✓✓ |
10375 |
if (per_process::cli_options->enable_fips_crypto || |
111 |
✓✓ | 5187 |
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 |
5186 |
return true; |
|
125 |
} |
||
126 |
|||
127 |
6034 |
bool InitCryptoOnce(Isolate* isolate) { |
|
128 |
static uv_once_t init_once = UV_ONCE_INIT; |
||
129 |
12068 |
TryCatch try_catch{isolate}; |
|
130 |
6034 |
uv_once(&init_once, InitCryptoOnce); |
|
131 |
✗✓✗✗ ✗✓ |
6034 |
if (try_catch.HasCaught() && !try_catch.HasTerminated()) { |
132 |
try_catch.ReThrow(); |
||
133 |
return false; |
||
134 |
} |
||
135 |
6034 |
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 |
5194 |
void InitCryptoOnce() { |
|
143 |
10388 |
Mutex::ScopedLock lock(per_process::cli_options_mutex); |
|
144 |
10388 |
Mutex::ScopedLock fips_lock(fips_mutex); |
|
145 |
#ifndef OPENSSL_IS_BORINGSSL |
||
146 |
5194 |
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 |
✗✓ | 5194 |
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 |
5194 |
OPENSSL_init_ssl(0, settings); |
|
167 |
5194 |
OPENSSL_INIT_free(settings); |
|
168 |
5194 |
settings = nullptr; |
|
169 |
|||
170 |
#ifndef _WIN32 |
||
171 |
✓✓ | 5194 |
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 |
5194 |
sk_SSL_COMP_zero(SSL_COMP_get_compression_methods()); |
|
194 |
|||
195 |
#ifndef OPENSSL_NO_ENGINE |
||
196 |
5194 |
ERR_load_ENGINE_strings(); |
|
197 |
5194 |
ENGINE_load_builtin_engines(); |
|
198 |
#endif // !OPENSSL_NO_ENGINE |
||
199 |
|||
200 |
5194 |
NodeBIO::GetMethod(); |
|
201 |
5194 |
} |
|
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 |
6417 |
bool CryptoErrorStore::Empty() const { |
|
275 |
6417 |
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 |
18391 |
ByteSource::ByteSource(ByteSource&& other) noexcept |
|
320 |
18391 |
: data_(other.data_), |
|
321 |
18391 |
allocated_data_(other.allocated_data_), |
|
322 |
36782 |
size_(other.size_) { |
|
323 |
18391 |
other.allocated_data_ = nullptr; |
|
324 |
18391 |
} |
|
325 |
|||
326 |
125820 |
ByteSource::~ByteSource() { |
|
327 |
62910 |
OPENSSL_clear_free(allocated_data_, size_); |
|
328 |
62910 |
} |
|
329 |
|||
330 |
void ByteSource::reset() { |
||
331 |
OPENSSL_clear_free(allocated_data_, size_); |
||
332 |
data_ = nullptr; |
||
333 |
size_ = 0; |
||
334 |
} |
||
335 |
|||
336 |
11924 |
ByteSource& ByteSource::operator=(ByteSource&& other) noexcept { |
|
337 |
✓✗ | 11924 |
if (&other != this) { |
338 |
11924 |
OPENSSL_clear_free(allocated_data_, size_); |
|
339 |
11924 |
data_ = other.data_; |
|
340 |
11924 |
allocated_data_ = other.allocated_data_; |
|
341 |
11924 |
other.allocated_data_ = nullptr; |
|
342 |
11924 |
size_ = other.size_; |
|
343 |
} |
||
344 |
11924 |
return *this; |
|
345 |
} |
||
346 |
|||
347 |
2960 |
std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore() { |
|
348 |
// It's ok for allocated_data_ to be nullptr but |
||
349 |
// only if size_ is zero. |
||
350 |
✓✓✗✓ |
2960 |
CHECK_IMPLIES(size_ > 0, allocated_data_ != nullptr); |
351 |
std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore( |
||
352 |
2960 |
allocated_data_, |
|
353 |
size(), |
||
354 |
2955 |
[](void* data, size_t length, void* deleter_data) { |
|
355 |
2955 |
OPENSSL_clear_free(deleter_data, length); |
|
356 |
2960 |
}, allocated_data_); |
|
357 |
✗✓ | 2960 |
CHECK(ptr); |
358 |
2960 |
allocated_data_ = nullptr; |
|
359 |
2960 |
data_ = nullptr; |
|
360 |
2960 |
size_ = 0; |
|
361 |
2960 |
return ptr; |
|
362 |
} |
||
363 |
|||
364 |
2960 |
Local<ArrayBuffer> ByteSource::ToArrayBuffer(Environment* env) { |
|
365 |
2960 |
std::unique_ptr<BackingStore> store = ReleaseToBackingStore(); |
|
366 |
2960 |
return ArrayBuffer::New(env->isolate(), std::move(store)); |
|
367 |
} |
||
368 |
|||
369 |
17 |
MaybeLocal<Uint8Array> ByteSource::ToBuffer(Environment* env) { |
|
370 |
17 |
Local<ArrayBuffer> ab = ToArrayBuffer(env); |
|
371 |
17 |
return Buffer::New(env, ab, 0, ab->ByteLength()); |
|
372 |
} |
||
373 |
|||
374 |
20188 |
const char* ByteSource::get() const { |
|
375 |
20188 |
return data_; |
|
376 |
} |
||
377 |
|||
378 |
26310 |
size_t ByteSource::size() const { |
|
379 |
26310 |
return size_; |
|
380 |
} |
||
381 |
|||
382 |
505 |
ByteSource ByteSource::FromBIO(const BIOPointer& bio) { |
|
383 |
✗✓ | 505 |
CHECK(bio); |
384 |
BUF_MEM* bptr; |
||
385 |
505 |
BIO_get_mem_ptr(bio.get(), &bptr); |
|
386 |
505 |
char* data = MallocOpenSSL<char>(bptr->length); |
|
387 |
505 |
memcpy(data, bptr->data, bptr->length); |
|
388 |
505 |
return Allocated(data, bptr->length); |
|
389 |
} |
||
390 |
|||
391 |
3111 |
ByteSource ByteSource::FromEncodedString(Environment* env, |
|
392 |
Local<String> key, |
||
393 |
enum encoding enc) { |
||
394 |
3111 |
size_t length = 0; |
|
395 |
3111 |
size_t actual = 0; |
|
396 |
3111 |
char* data = nullptr; |
|
397 |
|||
398 |
✓✗✓✗ ✓✗ |
6222 |
if (StringBytes::Size(env->isolate(), key, enc).To(&length) && length > 0) { |
399 |
3111 |
data = MallocOpenSSL<char>(length); |
|
400 |
3111 |
actual = StringBytes::Write(env->isolate(), data, length, key, enc); |
|
401 |
|||
402 |
✗✓ | 3111 |
CHECK(actual <= length); |
403 |
|||
404 |
✗✓ | 3111 |
if (actual == 0) { |
405 |
OPENSSL_clear_free(data, length); |
||
406 |
data = nullptr; |
||
407 |
✗✓ | 3111 |
} else if (actual < length) { |
408 |
data = reinterpret_cast<char*>(OPENSSL_realloc(data, actual)); |
||
409 |
} |
||
410 |
} |
||
411 |
|||
412 |
3111 |
return Allocated(data, actual); |
|
413 |
} |
||
414 |
|||
415 |
2685 |
ByteSource ByteSource::FromStringOrBuffer(Environment* env, |
|
416 |
Local<Value> value) { |
||
417 |
2685 |
return IsAnyByteSource(value) ? FromBuffer(value) |
|
418 |
✓✗ | 2685 |
: FromString(env, value.As<String>()); |
419 |
} |
||
420 |
|||
421 |
24 |
ByteSource ByteSource::FromString(Environment* env, Local<String> str, |
|
422 |
bool ntc) { |
||
423 |
✗✓ | 48 |
CHECK(str->IsString()); |
424 |
24 |
size_t size = str->Utf8Length(env->isolate()); |
|
425 |
✗✓ | 24 |
size_t alloc_size = ntc ? size + 1 : size; |
426 |
24 |
char* data = MallocOpenSSL<char>(alloc_size); |
|
427 |
24 |
int opts = String::NO_OPTIONS; |
|
428 |
✓✗ | 24 |
if (!ntc) opts |= String::NO_NULL_TERMINATION; |
429 |
24 |
str->WriteUtf8(env->isolate(), data, alloc_size, nullptr, opts); |
|
430 |
24 |
return Allocated(data, size); |
|
431 |
} |
||
432 |
|||
433 |
2687 |
ByteSource ByteSource::FromBuffer(Local<Value> buffer, bool ntc) { |
|
434 |
5374 |
ArrayBufferOrViewContents<char> buf(buffer); |
|
435 |
✗✓ | 2687 |
return ntc ? buf.ToNullTerminatedCopy() : buf.ToByteSource(); |
436 |
} |
||
437 |
|||
438 |
1558 |
ByteSource ByteSource::FromSecretKeyBytes( |
|
439 |
Environment* env, |
||
440 |
Local<Value> value) { |
||
441 |
// A key can be passed as a string, buffer or KeyObject with type 'secret'. |
||
442 |
// If it is a string, we need to convert it to a buffer. We are not doing that |
||
443 |
// in JS to avoid creating an unprotected copy on the heap. |
||
444 |
✓✗✓✓ |
3116 |
return value->IsString() || IsAnyByteSource(value) ? |
445 |
ByteSource::FromStringOrBuffer(env, value) : |
||
446 |
1558 |
ByteSource::FromSymmetricKeyObjectHandle(value); |
|
447 |
} |
||
448 |
|||
449 |
ByteSource ByteSource::NullTerminatedCopy(Environment* env, |
||
450 |
Local<Value> value) { |
||
451 |
return Buffer::HasInstance(value) ? FromBuffer(value, true) |
||
452 |
: FromString(env, value.As<String>(), true); |
||
453 |
} |
||
454 |
|||
455 |
14 |
ByteSource ByteSource::FromSymmetricKeyObjectHandle(Local<Value> handle) { |
|
456 |
✗✓ | 14 |
CHECK(handle->IsObject()); |
457 |
14 |
KeyObjectHandle* key = Unwrap<KeyObjectHandle>(handle.As<Object>()); |
|
458 |
✗✓ | 14 |
CHECK_NOT_NULL(key); |
459 |
14 |
return Foreign(key->Data()->GetSymmetricKey(), |
|
460 |
28 |
key->Data()->GetSymmetricKeySize()); |
|
461 |
} |
||
462 |
|||
463 |
21925 |
ByteSource::ByteSource(const char* data, char* allocated_data, size_t size) |
|
464 |
: data_(data), |
||
465 |
allocated_data_(allocated_data), |
||
466 |
21925 |
size_(size) {} |
|
467 |
|||
468 |
16820 |
ByteSource ByteSource::Allocated(char* data, size_t size) { |
|
469 |
16820 |
return ByteSource(data, data, size); |
|
470 |
} |
||
471 |
|||
472 |
5105 |
ByteSource ByteSource::Foreign(const char* data, size_t size) { |
|
473 |
5105 |
return ByteSource(data, nullptr, size); |
|
474 |
} |
||
475 |
|||
476 |
namespace error { |
||
477 |
104 |
Maybe<bool> Decorate(Environment* env, Local<Object> obj, |
|
478 |
unsigned long err) { // NOLINT(runtime/int) |
||
479 |
✓✓ | 104 |
if (err == 0) return Just(true); // No decoration necessary. |
480 |
|||
481 |
93 |
const char* ls = ERR_lib_error_string(err); |
|
482 |
93 |
const char* fs = ERR_func_error_string(err); |
|
483 |
93 |
const char* rs = ERR_reason_error_string(err); |
|
484 |
|||
485 |
93 |
Isolate* isolate = env->isolate(); |
|
486 |
93 |
Local<Context> context = isolate->GetCurrentContext(); |
|
487 |
|||
488 |
✓✗ | 93 |
if (ls != nullptr) { |
489 |
186 |
if (obj->Set(context, env->library_string(), |
|
490 |
✓✓ | 372 |
OneByteString(isolate, ls)).IsNothing()) { |
491 |
1 |
return Nothing<bool>(); |
|
492 |
} |
||
493 |
} |
||
494 |
✗✓ | 92 |
if (fs != nullptr) { |
495 |
if (obj->Set(context, env->function_string(), |
||
496 |
OneByteString(isolate, fs)).IsNothing()) { |
||
497 |
return Nothing<bool>(); |
||
498 |
} |
||
499 |
} |
||
500 |
✓✗ | 92 |
if (rs != nullptr) { |
501 |
184 |
if (obj->Set(context, env->reason_string(), |
|
502 |
✗✓ | 368 |
OneByteString(isolate, rs)).IsNothing()) { |
503 |
return Nothing<bool>(); |
||
504 |
} |
||
505 |
|||
506 |
// SSL has no API to recover the error name from the number, so we |
||
507 |
// transform reason strings like "this error" to "ERR_SSL_THIS_ERROR", |
||
508 |
// which ends up being close to the original error macro name. |
||
509 |
92 |
std::string reason(rs); |
|
510 |
|||
511 |
✓✓ | 1754 |
for (auto& c : reason) { |
512 |
✓✓ | 1662 |
if (c == ' ') |
513 |
183 |
c = '_'; |
|
514 |
else |
||
515 |
1479 |
c = ToUpper(c); |
|
516 |
} |
||
517 |
|||
518 |
#define OSSL_ERROR_CODES_MAP(V) \ |
||
519 |
V(SYS) \ |
||
520 |
V(BN) \ |
||
521 |
V(RSA) \ |
||
522 |
V(DH) \ |
||
523 |
V(EVP) \ |
||
524 |
V(BUF) \ |
||
525 |
V(OBJ) \ |
||
526 |
V(PEM) \ |
||
527 |
V(DSA) \ |
||
528 |
V(X509) \ |
||
529 |
V(ASN1) \ |
||
530 |
V(CONF) \ |
||
531 |
V(CRYPTO) \ |
||
532 |
V(EC) \ |
||
533 |
V(SSL) \ |
||
534 |
V(BIO) \ |
||
535 |
V(PKCS7) \ |
||
536 |
V(X509V3) \ |
||
537 |
V(PKCS12) \ |
||
538 |
V(RAND) \ |
||
539 |
V(DSO) \ |
||
540 |
V(ENGINE) \ |
||
541 |
V(OCSP) \ |
||
542 |
V(UI) \ |
||
543 |
V(COMP) \ |
||
544 |
V(ECDSA) \ |
||
545 |
V(ECDH) \ |
||
546 |
V(OSSL_STORE) \ |
||
547 |
V(FIPS) \ |
||
548 |
V(CMS) \ |
||
549 |
V(TS) \ |
||
550 |
V(HMAC) \ |
||
551 |
V(CT) \ |
||
552 |
V(ASYNC) \ |
||
553 |
V(KDF) \ |
||
554 |
V(SM2) \ |
||
555 |
V(USER) \ |
||
556 |
|||
557 |
#define V(name) case ERR_LIB_##name: lib = #name "_"; break; |
||
558 |
92 |
const char* lib = ""; |
|
559 |
92 |
const char* prefix = "OSSL_"; |
|
560 |
✗✗✓✓ ✓✗✗✗ ✗✓✗✗ ✓✗✓✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✓ |
92 |
switch (ERR_GET_LIB(err)) { OSSL_ERROR_CODES_MAP(V) } |
561 |
#undef V |
||
562 |
#undef OSSL_ERROR_CODES_MAP |
||
563 |
// Don't generate codes like "ERR_OSSL_SSL_". |
||
564 |
✓✗✓✓ |
92 |
if (lib && strcmp(lib, "SSL_") == 0) |
565 |
6 |
prefix = ""; |
|
566 |
|||
567 |
// All OpenSSL reason strings fit in a single 80-column macro definition, |
||
568 |
// all prefix lengths are <= 10, and ERR_OSSL_ is 9, so 128 is more than |
||
569 |
// sufficient. |
||
570 |
char code[128]; |
||
571 |
92 |
snprintf(code, sizeof(code), "ERR_%s%s%s", prefix, lib, reason.c_str()); |
|
572 |
|||
573 |
184 |
if (obj->Set(env->isolate()->GetCurrentContext(), |
|
574 |
env->code_string(), |
||
575 |
✗✓ | 368 |
OneByteString(env->isolate(), code)).IsNothing()) |
576 |
return Nothing<bool>(); |
||
577 |
} |
||
578 |
|||
579 |
92 |
return Just(true); |
|
580 |
} |
||
581 |
} // namespace error |
||
582 |
|||
583 |
104 |
void ThrowCryptoError(Environment* env, |
|
584 |
unsigned long err, // NOLINT(runtime/int) |
||
585 |
// Default, only used if there is no SSL `err` which can |
||
586 |
// be used to create a long-style message string. |
||
587 |
const char* message) { |
||
588 |
104 |
char message_buffer[128] = {0}; |
|
589 |
✓✓✗✓ |
104 |
if (err != 0 || message == nullptr) { |
590 |
93 |
ERR_error_string_n(err, message_buffer, sizeof(message_buffer)); |
|
591 |
93 |
message = message_buffer; |
|
592 |
} |
||
593 |
104 |
HandleScope scope(env->isolate()); |
|
594 |
Local<String> exception_string; |
||
595 |
Local<Value> exception; |
||
596 |
Local<Object> obj; |
||
597 |
✗✓ | 208 |
if (!String::NewFromUtf8(env->isolate(), message).ToLocal(&exception_string)) |
598 |
return; |
||
599 |
104 |
CryptoErrorStore errors; |
|
600 |
104 |
errors.Capture(); |
|
601 |
104 |
if (!errors.ToException(env, exception_string).ToLocal(&exception) || |
|
602 |
✓✗✓✗ |
416 |
!exception->ToObject(env->context()).ToLocal(&obj) || |
603 |
✓✓✓✓ |
312 |
error::Decorate(env, obj, err).IsNothing()) { |
604 |
1 |
return; |
|
605 |
} |
||
606 |
103 |
env->isolate()->ThrowException(exception); |
|
607 |
} |
||
608 |
|||
609 |
#ifndef OPENSSL_NO_ENGINE |
||
610 |
11 |
EnginePointer LoadEngineById(const char* id, CryptoErrorStore* errors) { |
|
611 |
22 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
|
612 |
|||
613 |
11 |
EnginePointer engine(ENGINE_by_id(id)); |
|
614 |
✓✓ | 11 |
if (!engine) { |
615 |
// Engine not found, try loading dynamically. |
||
616 |
2 |
engine = EnginePointer(ENGINE_by_id("dynamic")); |
|
617 |
✓✗ | 2 |
if (engine) { |
618 |
✓✗✓✗ ✓✗ |
4 |
if (!ENGINE_ctrl_cmd_string(engine.get(), "SO_PATH", id, 0) || |
619 |
2 |
!ENGINE_ctrl_cmd_string(engine.get(), "LOAD", nullptr, 0)) { |
|
620 |
2 |
engine.reset(); |
|
621 |
} |
||
622 |
} |
||
623 |
} |
||
624 |
|||
625 |
✓✓✗✓ ✗✓ |
11 |
if (!engine && errors != nullptr) { |
626 |
errors->Capture(); |
||
627 |
if (errors->Empty()) { |
||
628 |
errors->Insert(NodeCryptoError::ENGINE_NOT_FOUND, id); |
||
629 |
} |
||
630 |
} |
||
631 |
|||
632 |
11 |
return engine; |
|
633 |
} |
||
634 |
|||
635 |
11 |
bool SetEngine(const char* id, uint32_t flags, CryptoErrorStore* errors) { |
|
636 |
11 |
ClearErrorOnReturn clear_error_on_return; |
|
637 |
22 |
EnginePointer engine = LoadEngineById(id, errors); |
|
638 |
✓✓ | 11 |
if (!engine) |
639 |
2 |
return false; |
|
640 |
|||
641 |
✗✓ | 9 |
if (!ENGINE_set_default(engine.get(), flags)) { |
642 |
if (errors != nullptr) |
||
643 |
errors->Capture(); |
||
644 |
return false; |
||
645 |
} |
||
646 |
|||
647 |
9 |
return true; |
|
648 |
} |
||
649 |
|||
650 |
11 |
void SetEngine(const FunctionCallbackInfo<Value>& args) { |
|
651 |
11 |
Environment* env = Environment::GetCurrent(args); |
|
652 |
✓✗✗✓ ✗✓ |
33 |
CHECK(args.Length() >= 2 && args[0]->IsString()); |
653 |
uint32_t flags; |
||
654 |
✗✓ | 22 |
if (!args[1]->Uint32Value(env->context()).To(&flags)) return; |
655 |
|||
656 |
11 |
const node::Utf8Value engine_id(env->isolate(), args[0]); |
|
657 |
|||
658 |
✓✓ | 22 |
args.GetReturnValue().Set(SetEngine(*engine_id, flags)); |
659 |
} |
||
660 |
#endif // !OPENSSL_NO_ENGINE |
||
661 |
|||
662 |
2603 |
MaybeLocal<Value> EncodeBignum( |
|
663 |
Environment* env, |
||
664 |
const BIGNUM* bn, |
||
665 |
int size, |
||
666 |
Local<Value>* error) { |
||
667 |
5206 |
std::vector<uint8_t> buf(size); |
|
668 |
✗✓ | 2603 |
CHECK_EQ(BN_bn2binpad(bn, buf.data(), size), size); |
669 |
return StringBytes::Encode( |
||
670 |
env->isolate(), |
||
671 |
2603 |
reinterpret_cast<const char*>(buf.data()), |
|
672 |
buf.size(), |
||
673 |
BASE64URL, |
||
674 |
5206 |
error); |
|
675 |
} |
||
676 |
|||
677 |
✗✓ | 2603 |
Maybe<bool> SetEncodedValue( |
678 |
Environment* env, |
||
679 |
Local<Object> target, |
||
680 |
Local<String> name, |
||
681 |
const BIGNUM* bn, |
||
682 |
int size) { |
||
683 |
Local<Value> value; |
||
684 |
Local<Value> error; |
||
685 |
✗✓ | 2603 |
CHECK_NOT_NULL(bn); |
686 |
✓✓ | 2603 |
if (size == 0) |
687 |
2094 |
size = BN_num_bytes(bn); |
|
688 |
✗✓ | 5206 |
if (!EncodeBignum(env, bn, size, &error).ToLocal(&value)) { |
689 |
if (!error.IsEmpty()) |
||
690 |
env->isolate()->ThrowException(error); |
||
691 |
return Nothing<bool>(); |
||
692 |
} |
||
693 |
2603 |
return target->Set(env->context(), name, value); |
|
694 |
} |
||
695 |
|||
696 |
5294 |
CryptoJobMode GetCryptoJobMode(v8::Local<v8::Value> args) { |
|
697 |
✗✓ | 5294 |
CHECK(args->IsUint32()); |
698 |
5294 |
uint32_t mode = args.As<v8::Uint32>()->Value(); |
|
699 |
✗✓ | 5294 |
CHECK_LE(mode, kCryptoJobSync); |
700 |
5294 |
return static_cast<CryptoJobMode>(mode); |
|
701 |
} |
||
702 |
|||
703 |
namespace { |
||
704 |
// SecureBuffer uses openssl to allocate a Uint8Array using |
||
705 |
// OPENSSL_secure_malloc. Because we do not yet actually |
||
706 |
// make use of secure heap, this has the same semantics as |
||
707 |
// using OPENSSL_malloc. However, if the secure heap is |
||
708 |
// initialized, SecureBuffer will automatically use it. |
||
709 |
✓✗ | 4 |
void SecureBuffer(const FunctionCallbackInfo<Value>& args) { |
710 |
✗✓ | 4 |
CHECK(args[0]->IsUint32()); |
711 |
4 |
Environment* env = Environment::GetCurrent(args); |
|
712 |
8 |
uint32_t len = args[0].As<Uint32>()->Value(); |
|
713 |
4 |
char* data = static_cast<char*>(OPENSSL_secure_malloc(len)); |
|
714 |
✗✓ | 4 |
if (data == nullptr) { |
715 |
// There's no memory available for the allocation. |
||
716 |
// Return nothing. |
||
717 |
return; |
||
718 |
} |
||
719 |
4 |
memset(data, 0, len); |
|
720 |
std::shared_ptr<BackingStore> store = |
||
721 |
4 |
ArrayBuffer::NewBackingStore( |
|
722 |
data, |
||
723 |
len, |
||
724 |
4 |
[](void* data, size_t len, void* deleter_data) { |
|
725 |
4 |
OPENSSL_secure_clear_free(data, len); |
|
726 |
4 |
}, |
|
727 |
4 |
data); |
|
728 |
4 |
Local<ArrayBuffer> buffer = ArrayBuffer::New(env->isolate(), store); |
|
729 |
8 |
args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len)); |
|
730 |
} |
||
731 |
|||
732 |
4 |
void SecureHeapUsed(const FunctionCallbackInfo<Value>& args) { |
|
733 |
4 |
Environment* env = Environment::GetCurrent(args); |
|
734 |
✓✗ | 4 |
if (CRYPTO_secure_malloc_initialized()) |
735 |
8 |
args.GetReturnValue().Set( |
|
736 |
4 |
BigInt::New(env->isolate(), CRYPTO_secure_used())); |
|
737 |
4 |
} |
|
738 |
} // namespace |
||
739 |
|||
740 |
namespace Util { |
||
741 |
856 |
void Initialize(Environment* env, Local<Object> target) { |
|
742 |
#ifndef OPENSSL_NO_ENGINE |
||
743 |
856 |
env->SetMethod(target, "setEngine", SetEngine); |
|
744 |
#endif // !OPENSSL_NO_ENGINE |
||
745 |
|||
746 |
856 |
env->SetMethodNoSideEffect(target, "getFipsCrypto", GetFipsCrypto); |
|
747 |
856 |
env->SetMethod(target, "setFipsCrypto", SetFipsCrypto); |
|
748 |
856 |
env->SetMethodNoSideEffect(target, "testFipsCrypto", TestFipsCrypto); |
|
749 |
|||
750 |
2568 |
NODE_DEFINE_CONSTANT(target, kCryptoJobAsync); |
|
751 |
1712 |
NODE_DEFINE_CONSTANT(target, kCryptoJobSync); |
|
752 |
|||
753 |
856 |
env->SetMethod(target, "secureBuffer", SecureBuffer); |
|
754 |
856 |
env->SetMethod(target, "secureHeapUsed", SecureHeapUsed); |
|
755 |
856 |
} |
|
756 |
5184 |
void RegisterExternalReferences(ExternalReferenceRegistry* registry) { |
|
757 |
#ifndef OPENSSL_NO_ENGINE |
||
758 |
5184 |
registry->Register(SetEngine); |
|
759 |
#endif // !OPENSSL_NO_ENGINE |
||
760 |
|||
761 |
5184 |
registry->Register(GetFipsCrypto); |
|
762 |
5184 |
registry->Register(SetFipsCrypto); |
|
763 |
5184 |
registry->Register(TestFipsCrypto); |
|
764 |
5184 |
registry->Register(SecureBuffer); |
|
765 |
5184 |
registry->Register(SecureHeapUsed); |
|
766 |
5184 |
} |
|
767 |
|||
768 |
} // namespace Util |
||
769 |
|||
770 |
} // namespace crypto |
||
771 |
} // namespace node |
Generated by: GCOVR (Version 4.2) |