GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
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/err.h> |
||
16 |
#include <openssl/evp.h> |
||
17 |
#include <openssl/ec.h> |
||
18 |
#include <openssl/kdf.h> |
||
19 |
#include <openssl/rsa.h> |
||
20 |
#include <openssl/dsa.h> |
||
21 |
#include <openssl/ssl.h> |
||
22 |
#ifndef OPENSSL_NO_ENGINE |
||
23 |
# include <openssl/engine.h> |
||
24 |
#endif // !OPENSSL_NO_ENGINE |
||
25 |
// The FIPS-related functions are only available |
||
26 |
// when the OpenSSL itself was compiled with FIPS support. |
||
27 |
#if defined(OPENSSL_FIPS) && OPENSSL_VERSION_MAJOR < 3 |
||
28 |
# include <openssl/fips.h> |
||
29 |
#endif // OPENSSL_FIPS |
||
30 |
|||
31 |
#include <algorithm> |
||
32 |
#include <climits> |
||
33 |
#include <cstdio> |
||
34 |
#include <memory> |
||
35 |
#include <optional> |
||
36 |
#include <string> |
||
37 |
#include <vector> |
||
38 |
|||
39 |
namespace node { |
||
40 |
namespace crypto { |
||
41 |
// Currently known sizes of commonly used OpenSSL struct sizes. |
||
42 |
// OpenSSL considers it's various structs to be opaque and the |
||
43 |
// sizes may change from one version of OpenSSL to another, so |
||
44 |
// these values should not be trusted to remain static. These |
||
45 |
// are provided to allow for some close to reasonable memory |
||
46 |
// tracking. |
||
47 |
constexpr size_t kSizeOf_DH = 144; |
||
48 |
constexpr size_t kSizeOf_EC_KEY = 80; |
||
49 |
constexpr size_t kSizeOf_EVP_CIPHER_CTX = 168; |
||
50 |
constexpr size_t kSizeOf_EVP_MD_CTX = 48; |
||
51 |
constexpr size_t kSizeOf_EVP_PKEY = 72; |
||
52 |
constexpr size_t kSizeOf_EVP_PKEY_CTX = 80; |
||
53 |
constexpr size_t kSizeOf_HMAC_CTX = 32; |
||
54 |
|||
55 |
// Define smart pointers for the most commonly used OpenSSL types: |
||
56 |
using X509Pointer = DeleteFnPtr<X509, X509_free>; |
||
57 |
using BIOPointer = DeleteFnPtr<BIO, BIO_free_all>; |
||
58 |
using SSLCtxPointer = DeleteFnPtr<SSL_CTX, SSL_CTX_free>; |
||
59 |
using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>; |
||
60 |
using SSLPointer = DeleteFnPtr<SSL, SSL_free>; |
||
61 |
using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>; |
||
62 |
using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>; |
||
63 |
using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>; |
||
64 |
using EVPMDPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>; |
||
65 |
using RSAPointer = DeleteFnPtr<RSA, RSA_free>; |
||
66 |
using ECPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>; |
||
67 |
using BignumPointer = DeleteFnPtr<BIGNUM, BN_free>; |
||
68 |
using BignumCtxPointer = DeleteFnPtr<BN_CTX, BN_CTX_free>; |
||
69 |
using NetscapeSPKIPointer = DeleteFnPtr<NETSCAPE_SPKI, NETSCAPE_SPKI_free>; |
||
70 |
using ECGroupPointer = DeleteFnPtr<EC_GROUP, EC_GROUP_free>; |
||
71 |
using ECPointPointer = DeleteFnPtr<EC_POINT, EC_POINT_free>; |
||
72 |
using ECKeyPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>; |
||
73 |
using DHPointer = DeleteFnPtr<DH, DH_free>; |
||
74 |
using ECDSASigPointer = DeleteFnPtr<ECDSA_SIG, ECDSA_SIG_free>; |
||
75 |
using HMACCtxPointer = DeleteFnPtr<HMAC_CTX, HMAC_CTX_free>; |
||
76 |
using CipherCtxPointer = DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>; |
||
77 |
using RsaPointer = DeleteFnPtr<RSA, RSA_free>; |
||
78 |
using DsaPointer = DeleteFnPtr<DSA, DSA_free>; |
||
79 |
using DsaSigPointer = DeleteFnPtr<DSA_SIG, DSA_SIG_free>; |
||
80 |
|||
81 |
// Our custom implementation of the certificate verify callback |
||
82 |
// used when establishing a TLS handshake. Because we cannot perform |
||
83 |
// I/O quickly enough with X509_STORE_CTX_ APIs in this callback, |
||
84 |
// we ignore preverify_ok errors here and let the handshake continue. |
||
85 |
// In other words, this VerifyCallback is a non-op. It is imperative |
||
86 |
// that the user user Connection::VerifyError after the `secure` |
||
87 |
// callback has been made. |
||
88 |
extern int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx); |
||
89 |
|||
90 |
bool ProcessFipsOptions(); |
||
91 |
|||
92 |
bool InitCryptoOnce(v8::Isolate* isolate); |
||
93 |
void InitCryptoOnce(); |
||
94 |
|||
95 |
void InitCrypto(v8::Local<v8::Object> target); |
||
96 |
|||
97 |
extern void UseExtraCaCerts(const std::string& file); |
||
98 |
|||
99 |
// Forcibly clear OpenSSL's error stack on return. This stops stale errors |
||
100 |
// from popping up later in the lifecycle of crypto operations where they |
||
101 |
// would cause spurious failures. It's a rather blunt method, though. |
||
102 |
// ERR_clear_error() isn't necessarily cheap either. |
||
103 |
struct ClearErrorOnReturn { |
||
104 |
11209 |
~ClearErrorOnReturn() { ERR_clear_error(); } |
|
105 |
}; |
||
106 |
|||
107 |
// Pop errors from OpenSSL's error stack that were added |
||
108 |
// between when this was constructed and destructed. |
||
109 |
struct MarkPopErrorOnReturn { |
||
110 |
25777 |
MarkPopErrorOnReturn() { ERR_set_mark(); } |
|
111 |
25776 |
~MarkPopErrorOnReturn() { ERR_pop_to_mark(); } |
|
112 |
}; |
||
113 |
|||
114 |
struct CSPRNGResult { |
||
115 |
const bool ok; |
||
116 |
24275 |
MUST_USE_RESULT bool is_ok() const { return ok; } |
|
117 |
9813 |
MUST_USE_RESULT bool is_err() const { return !ok; } |
|
118 |
}; |
||
119 |
|||
120 |
// Either succeeds with exactly |length| bytes of cryptographically |
||
121 |
// strong pseudo-random data, or fails. This function may block. |
||
122 |
// Don't assume anything about the contents of |buffer| on error. |
||
123 |
// As a special case, |length == 0| can be used to check if the CSPRNG |
||
124 |
// is properly seeded without consuming entropy. |
||
125 |
MUST_USE_RESULT CSPRNGResult CSPRNG(void* buffer, size_t length); |
||
126 |
|||
127 |
int PasswordCallback(char* buf, int size, int rwflag, void* u); |
||
128 |
|||
129 |
int NoPasswordCallback(char* buf, int size, int rwflag, void* u); |
||
130 |
|||
131 |
// Decode is used by the various stream-based crypto utilities to decode |
||
132 |
// string input. |
||
133 |
template <typename T> |
||
134 |
3018 |
void Decode(const v8::FunctionCallbackInfo<v8::Value>& args, |
|
135 |
void (*callback)(T*, const v8::FunctionCallbackInfo<v8::Value>&, |
||
136 |
const char*, size_t)) { |
||
137 |
T* ctx; |
||
138 |
✗✓✗✓ |
3018 |
ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder()); |
139 |
|||
140 |
✓✓✓✓ |
9054 |
if (args[0]->IsString()) { |
141 |
3272 |
StringBytes::InlineDecoder decoder; |
|
142 |
1636 |
Environment* env = Environment::GetCurrent(args); |
|
143 |
1636 |
enum encoding enc = ParseEncoding(env->isolate(), args[1], UTF8); |
|
144 |
✗✓✗✓ |
4908 |
if (decoder.Decode(env, args[0].As<v8::String>(), enc).IsNothing()) |
145 |
return; |
||
146 |
✓✗✓✗ |
1636 |
callback(ctx, args, decoder.out(), decoder.size()); |
147 |
} else { |
||
148 |
1382 |
ArrayBufferViewContents<char> buf(args[0]); |
|
149 |
1382 |
callback(ctx, args, buf.data(), buf.length()); |
|
150 |
} |
||
151 |
} |
||
152 |
|||
153 |
#define NODE_CRYPTO_ERROR_CODES_MAP(V) \ |
||
154 |
V(CIPHER_JOB_FAILED, "Cipher job failed") \ |
||
155 |
V(DERIVING_BITS_FAILED, "Deriving bits failed") \ |
||
156 |
V(ENGINE_NOT_FOUND, "Engine \"%s\" was not found") \ |
||
157 |
V(INVALID_KEY_TYPE, "Invalid key type") \ |
||
158 |
V(KEY_GENERATION_JOB_FAILED, "Key generation job failed") \ |
||
159 |
V(OK, "Ok") \ |
||
160 |
|||
161 |
enum class NodeCryptoError { |
||
162 |
#define V(CODE, DESCRIPTION) CODE, |
||
163 |
NODE_CRYPTO_ERROR_CODES_MAP(V) |
||
164 |
#undef V |
||
165 |
}; |
||
166 |
|||
167 |
// Utility struct used to harvest error information from openssl's error stack |
||
168 |
19329 |
struct CryptoErrorStore final : public MemoryRetainer { |
|
169 |
public: |
||
170 |
void Capture(); |
||
171 |
|||
172 |
bool Empty() const; |
||
173 |
|||
174 |
template <typename... Args> |
||
175 |
void Insert(const NodeCryptoError error, Args&&... args); |
||
176 |
|||
177 |
v8::MaybeLocal<v8::Value> ToException( |
||
178 |
Environment* env, |
||
179 |
v8::Local<v8::String> exception_string = v8::Local<v8::String>()) const; |
||
180 |
|||
181 |
3 |
SET_NO_MEMORY_INFO() |
|
182 |
3 |
SET_MEMORY_INFO_NAME(CryptoErrorStore) |
|
183 |
3 |
SET_SELF_SIZE(CryptoErrorStore) |
|
184 |
|||
185 |
private: |
||
186 |
std::vector<std::string> errors_; |
||
187 |
}; |
||
188 |
|||
189 |
template <typename... Args> |
||
190 |
14 |
void CryptoErrorStore::Insert(const NodeCryptoError error, Args&&... args) { |
|
191 |
14 |
const char* error_string = nullptr; |
|
192 |
✗✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗ |
14 |
switch (error) { |
193 |
#define V(CODE, DESCRIPTION) \ |
||
194 |
case NodeCryptoError::CODE: error_string = DESCRIPTION; break; |
||
195 |
NODE_CRYPTO_ERROR_CODES_MAP(V) |
||
196 |
#undef V |
||
197 |
} |
||
198 |
14 |
errors_.emplace_back(SPrintF(error_string, |
|
199 |
std::forward<Args>(args)...)); |
||
200 |
14 |
} |
|
201 |
|||
202 |
template <typename T> |
||
203 |
24851 |
T* MallocOpenSSL(size_t count) { |
|
204 |
24851 |
void* mem = OPENSSL_malloc(MultiplyWithOverflowCheck(count, sizeof(T))); |
|
205 |
✓✓✗✓ |
24851 |
CHECK_IMPLIES(mem == nullptr, count == 0); |
206 |
24851 |
return static_cast<T*>(mem); |
|
207 |
} |
||
208 |
|||
209 |
// A helper class representing a read-only byte array. When deallocated, its |
||
210 |
// contents are zeroed. |
||
211 |
class ByteSource { |
||
212 |
public: |
||
213 |
class Builder { |
||
214 |
public: |
||
215 |
// Allocates memory using OpenSSL's memory allocator. |
||
216 |
24849 |
explicit Builder(size_t size) |
|
217 |
24849 |
: data_(MallocOpenSSL<char>(size)), size_(size) {} |
|
218 |
|||
219 |
Builder(Builder&& other) = delete; |
||
220 |
Builder& operator=(Builder&& other) = delete; |
||
221 |
Builder(const Builder&) = delete; |
||
222 |
Builder& operator=(const Builder&) = delete; |
||
223 |
|||
224 |
24849 |
~Builder() { OPENSSL_clear_free(data_, size_); } |
|
225 |
|||
226 |
// Returns the underlying non-const pointer. |
||
227 |
template <typename T> |
||
228 |
26798 |
T* data() { |
|
229 |
26798 |
return reinterpret_cast<T*>(data_); |
|
230 |
} |
||
231 |
|||
232 |
// Returns the (allocated) size in bytes. |
||
233 |
13 |
size_t size() const { return size_; } |
|
234 |
|||
235 |
// Finalizes the Builder and returns a read-only view that is optionally |
||
236 |
// truncated. |
||
237 |
24761 |
ByteSource release(std::optional<size_t> resize = std::nullopt) && { |
|
238 |
✓✓ | 24761 |
if (resize) { |
239 |
✗✓ | 4683 |
CHECK_LE(*resize, size_); |
240 |
✓✓ | 4683 |
if (*resize == 0) { |
241 |
1 |
OPENSSL_clear_free(data_, size_); |
|
242 |
1 |
data_ = nullptr; |
|
243 |
} |
||
244 |
4683 |
size_ = *resize; |
|
245 |
} |
||
246 |
24761 |
ByteSource out = ByteSource::Allocated(data_, size_); |
|
247 |
24761 |
data_ = nullptr; |
|
248 |
24761 |
size_ = 0; |
|
249 |
24761 |
return out; |
|
250 |
} |
||
251 |
|||
252 |
private: |
||
253 |
void* data_; |
||
254 |
size_t size_; |
||
255 |
}; |
||
256 |
|||
257 |
34919 |
ByteSource() = default; |
|
258 |
ByteSource(ByteSource&& other) noexcept; |
||
259 |
~ByteSource(); |
||
260 |
|||
261 |
ByteSource& operator=(ByteSource&& other) noexcept; |
||
262 |
|||
263 |
ByteSource(const ByteSource&) = delete; |
||
264 |
ByteSource& operator=(const ByteSource&) = delete; |
||
265 |
|||
266 |
template <typename T = void> |
||
267 |
30423 |
const T* data() const { |
|
268 |
30423 |
return reinterpret_cast<const T*>(data_); |
|
269 |
} |
||
270 |
|||
271 |
45415 |
size_t size() const { return size_; } |
|
272 |
|||
273 |
2721 |
operator bool() const { return data_ != nullptr; } |
|
274 |
|||
275 |
2841 |
BignumPointer ToBN() const { |
|
276 |
2841 |
return BignumPointer(BN_bin2bn(data<unsigned char>(), size(), nullptr)); |
|
277 |
} |
||
278 |
|||
279 |
// Creates a v8::BackingStore that takes over responsibility for |
||
280 |
// any allocated data. The ByteSource will be reset with size = 0 |
||
281 |
// after being called. |
||
282 |
std::unique_ptr<v8::BackingStore> ReleaseToBackingStore(); |
||
283 |
|||
284 |
v8::Local<v8::ArrayBuffer> ToArrayBuffer(Environment* env); |
||
285 |
|||
286 |
v8::MaybeLocal<v8::Uint8Array> ToBuffer(Environment* env); |
||
287 |
|||
288 |
static ByteSource Allocated(void* data, size_t size); |
||
289 |
static ByteSource Foreign(const void* data, size_t size); |
||
290 |
|||
291 |
static ByteSource FromEncodedString(Environment* env, |
||
292 |
v8::Local<v8::String> value, |
||
293 |
enum encoding enc = BASE64); |
||
294 |
|||
295 |
static ByteSource FromStringOrBuffer(Environment* env, |
||
296 |
v8::Local<v8::Value> value); |
||
297 |
|||
298 |
static ByteSource FromString(Environment* env, |
||
299 |
v8::Local<v8::String> str, |
||
300 |
bool ntc = false); |
||
301 |
|||
302 |
static ByteSource FromBuffer(v8::Local<v8::Value> buffer, |
||
303 |
bool ntc = false); |
||
304 |
|||
305 |
static ByteSource FromBIO(const BIOPointer& bio); |
||
306 |
|||
307 |
static ByteSource NullTerminatedCopy(Environment* env, |
||
308 |
v8::Local<v8::Value> value); |
||
309 |
|||
310 |
static ByteSource FromSymmetricKeyObjectHandle(v8::Local<v8::Value> handle); |
||
311 |
|||
312 |
static ByteSource FromSecretKeyBytes( |
||
313 |
Environment* env, v8::Local<v8::Value> value); |
||
314 |
|||
315 |
private: |
||
316 |
const void* data_ = nullptr; |
||
317 |
void* allocated_data_ = nullptr; |
||
318 |
size_t size_ = 0; |
||
319 |
|||
320 |
31512 |
ByteSource(const void* data, void* allocated_data, size_t size) |
|
321 |
31512 |
: data_(data), allocated_data_(allocated_data), size_(size) {} |
|
322 |
}; |
||
323 |
|||
324 |
enum CryptoJobMode { |
||
325 |
kCryptoJobAsync, |
||
326 |
kCryptoJobSync |
||
327 |
}; |
||
328 |
|||
329 |
CryptoJobMode GetCryptoJobMode(v8::Local<v8::Value> args); |
||
330 |
|||
331 |
template <typename CryptoJobTraits> |
||
332 |
9407 |
class CryptoJob : public AsyncWrap, public ThreadPoolWork { |
|
333 |
public: |
||
334 |
using AdditionalParams = typename CryptoJobTraits::AdditionalParameters; |
||
335 |
|||
336 |
9408 |
explicit CryptoJob( |
|
337 |
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), |
||
344 |
mode_(mode), |
||
345 |
9408 |
params_(std::move(params)) { |
|
346 |
// If the CryptoJob is async, then the instance will be |
||
347 |
// cleaned up when AfterThreadPoolWork is called. |
||
348 |
✓✓✓✓ ✓✓ |
9408 |
if (mode == kCryptoJobSync) MakeWeak(); |
349 |
9408 |
} |
|
350 |
|||
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 |
|||
357 |
8105 |
void AfterThreadPoolWork(int status) override { |
|
358 |
8105 |
Environment* env = AsyncWrap::env(); |
|
359 |
✗✓✗✓ ✗✓ |
8105 |
CHECK_EQ(mode_, kCryptoJobAsync); |
360 |
✗✓✗✗ ✗✓✗✗ ✗✓✗✗ |
8105 |
CHECK(status == 0 || status == UV_ECANCELED); |
361 |
16210 |
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 |
✗✓✗✓ ✗✓ |
8105 |
if (status == UV_ECANCELED) return; |
367 |
✓✗✓✗ ✓✗ |
16210 |
v8::HandleScope handle_scope(env->isolate()); |
368 |
✓✗✓✗ ✓✗ |
16210 |
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 |
✓✓✓✓ ✓✓ |
24315 |
v8::Local<v8::Value> args[2]; |
374 |
{ |
||
375 |
16210 |
node::errors::TryCatchScope try_catch(env); |
|
376 |
8105 |
v8::Maybe<bool> ret = ptr->ToResult(&args[0], &args[1]); |
|
377 |
✗✓✓✓ ✗✓ |
8105 |
if (!ret.IsJust()) { |
378 |
✗✗✗✓ ✗✗ |
2 |
CHECK(try_catch.HasCaught()); |
379 |
2 |
exception = try_catch.Exception(); |
|
380 |
✗✓✗✓ ✗✓ |
8103 |
} else if (!ret.FromJust()) { |
381 |
return; |
||
382 |
} |
||
383 |
} |
||
384 |
|||
385 |
✓✗✓✓ ✓✗ |
8105 |
if (exception.IsEmpty()) { |
386 |
8103 |
ptr->MakeCallback(env->ondone_string(), arraysize(args), args); |
|
387 |
} else { |
||
388 |
2 |
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 |
|||
396 |
9403 |
CryptoJobMode mode() const { return mode_; } |
|
397 |
|||
398 |
9549 |
CryptoErrorStore* errors() { return &errors_; } |
|
399 |
|||
400 |
16882 |
AdditionalParams* params() { return ¶ms_; } |
|
401 |
|||
402 |
3 |
std::string MemoryInfoName() const override { |
|
403 |
3 |
return CryptoJobTraits::JobName; |
|
404 |
} |
||
405 |
|||
406 |
3 |
void MemoryInfo(MemoryTracker* tracker) const override { |
|
407 |
3 |
tracker->TrackField("params", params_); |
|
408 |
3 |
tracker->TrackField("errors", errors_); |
|
409 |
3 |
} |
|
410 |
|||
411 |
9403 |
static void Run(const v8::FunctionCallbackInfo<v8::Value>& args) { |
|
412 |
9403 |
Environment* env = Environment::GetCurrent(args); |
|
413 |
|||
414 |
CryptoJob<CryptoJobTraits>* job; |
||
415 |
✗✓✗✓ ✗✓ |
17509 |
ASSIGN_OR_RETURN_UNWRAP(&job, args.Holder()); |
416 |
✓✓✓✓ ✓✓ |
9403 |
if (job->mode() == kCryptoJobAsync) |
417 |
8106 |
return job->ScheduleWork(); |
|
418 |
|||
419 |
✓✓✓✓ ✓✓ |
3891 |
v8::Local<v8::Value> ret[2]; |
420 |
1297 |
env->PrintSyncTrace(); |
|
421 |
1297 |
job->DoThreadPoolWork(); |
|
422 |
1297 |
v8::Maybe<bool> result = job->ToResult(&ret[0], &ret[1]); |
|
423 |
✓✗✓✗ ✓✗✓✓ ✓✗✓✓ ✓✗✓✗ ✓✗ |
2591 |
if (result.IsJust() && result.FromJust()) { |
424 |
2588 |
args.GetReturnValue().Set( |
|
425 |
v8::Array::New(env->isolate(), ret, arraysize(ret))); |
||
426 |
} |
||
427 |
} |
||
428 |
|||
429 |
18078 |
static void Initialize( |
|
430 |
v8::FunctionCallback new_fn, |
||
431 |
Environment* env, |
||
432 |
v8::Local<v8::Object> target) { |
||
433 |
18078 |
v8::Isolate* isolate = env->isolate(); |
|
434 |
36156 |
v8::HandleScope scope(isolate); |
|
435 |
18078 |
v8::Local<v8::Context> context = env->context(); |
|
436 |
18078 |
v8::Local<v8::FunctionTemplate> job = NewFunctionTemplate(isolate, new_fn); |
|
437 |
18078 |
job->Inherit(AsyncWrap::GetConstructorTemplate(env)); |
|
438 |
36156 |
job->InstanceTemplate()->SetInternalFieldCount( |
|
439 |
AsyncWrap::kInternalFieldCount); |
||
440 |
18078 |
SetProtoMethod(isolate, job, "run", Run); |
|
441 |
18078 |
SetConstructorFunction(context, target, CryptoJobTraits::JobName, job); |
|
442 |
18078 |
} |
|
443 |
|||
444 |
127696 |
static void RegisterExternalReferences(v8::FunctionCallback new_fn, |
|
445 |
ExternalReferenceRegistry* registry) { |
||
446 |
127696 |
registry->Register(new_fn); |
|
447 |
127696 |
registry->Register(Run); |
|
448 |
127696 |
} |
|
449 |
|||
450 |
private: |
||
451 |
const CryptoJobMode mode_; |
||
452 |
CryptoErrorStore errors_; |
||
453 |
AdditionalParams params_; |
||
454 |
}; |
||
455 |
|||
456 |
template <typename DeriveBitsTraits> |
||
457 |
11050 |
class DeriveBitsJob final : public CryptoJob<DeriveBitsTraits> { |
|
458 |
public: |
||
459 |
using AdditionalParams = typename DeriveBitsTraits::AdditionalParameters; |
||
460 |
|||
461 |
5561 |
static void New(const v8::FunctionCallbackInfo<v8::Value>& args) { |
|
462 |
5561 |
Environment* env = Environment::GetCurrent(args); |
|
463 |
|||
464 |
5561 |
CryptoJobMode mode = GetCryptoJobMode(args[0]); |
|
465 |
|||
466 |
11086 |
AdditionalParams params; |
|
467 |
✓✓✓✓ ✓✓ |
11122 |
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 |
36 |
return; |
|
473 |
} |
||
474 |
|||
475 |
✓✓✓✓ ✓✓ |
5525 |
new DeriveBitsJob(env, args.This(), mode, std::move(params)); |
476 |
} |
||
477 |
|||
478 |
8646 |
static void Initialize( |
|
479 |
Environment* env, |
||
480 |
v8::Local<v8::Object> target) { |
||
481 |
8646 |
CryptoJob<DeriveBitsTraits>::Initialize(New, env, target); |
|
482 |
8646 |
} |
|
483 |
|||
484 |
61072 |
static void RegisterExternalReferences(ExternalReferenceRegistry* registry) { |
|
485 |
61072 |
CryptoJob<DeriveBitsTraits>::RegisterExternalReferences(New, registry); |
|
486 |
61072 |
} |
|
487 |
|||
488 |
5525 |
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 |
5525 |
std::move(params)) {} |
|
499 |
|||
500 |
5525 |
void DoThreadPoolWork() override { |
|
501 |
✓✓✗✓ ✗✓ |
11050 |
if (!DeriveBitsTraits::DeriveBits( |
502 |
AsyncWrap::env(), |
||
503 |
5525 |
*CryptoJob<DeriveBitsTraits>::params(), &out_)) { |
|
504 |
14 |
CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors(); |
|
505 |
14 |
errors->Capture(); |
|
506 |
✓✗✗✗ ✗✗ |
14 |
if (errors->Empty()) |
507 |
14 |
errors->Insert(NodeCryptoError::DERIVING_BITS_FAILED); |
|
508 |
14 |
return; |
|
509 |
} |
||
510 |
5511 |
success_ = true; |
|
511 |
} |
||
512 |
|||
513 |
5525 |
v8::Maybe<bool> ToResult( |
|
514 |
v8::Local<v8::Value>* err, |
||
515 |
v8::Local<v8::Value>* result) override { |
||
516 |
5525 |
Environment* env = AsyncWrap::env(); |
|
517 |
5525 |
CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors(); |
|
518 |
✓✓✓✗ ✓✗ |
5525 |
if (success_) { |
519 |
✗✓✗✓ ✗✓ |
5511 |
CHECK(errors->Empty()); |
520 |
11022 |
*err = v8::Undefined(env->isolate()); |
|
521 |
5511 |
return DeriveBitsTraits::EncodeOutput( |
|
522 |
env, |
||
523 |
5511 |
*CryptoJob<DeriveBitsTraits>::params(), |
|
524 |
&out_, |
||
525 |
5511 |
result); |
|
526 |
} |
||
527 |
|||
528 |
✗✓✗✗ ✗✗ |
14 |
if (errors->Empty()) |
529 |
errors->Capture(); |
||
530 |
✗✓✗✗ ✗✗ |
14 |
CHECK(!errors->Empty()); |
531 |
28 |
*result = v8::Undefined(env->isolate()); |
|
532 |
28 |
return v8::Just(errors->ToException(env).ToLocal(err)); |
|
533 |
} |
||
534 |
|||
535 |
3 |
SET_SELF_SIZE(DeriveBitsJob) |
|
536 |
3 |
void MemoryInfo(MemoryTracker* tracker) const override { |
|
537 |
3 |
tracker->TrackFieldWithSize("out", out_.size()); |
|
538 |
3 |
CryptoJob<DeriveBitsTraits>::MemoryInfo(tracker); |
|
539 |
3 |
} |
|
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 |
2506 |
inline EnginePointer() = default; |
|
556 |
|||
557 |
13 |
inline explicit EnginePointer(ENGINE* engine_, bool finish_on_exit_ = false) |
|
558 |
13 |
: engine(engine_), |
|
559 |
13 |
finish_on_exit(finish_on_exit_) {} |
|
560 |
|||
561 |
2 |
inline EnginePointer(EnginePointer&& other) noexcept |
|
562 |
2 |
: engine(other.engine), |
|
563 |
2 |
finish_on_exit(other.finish_on_exit) { |
|
564 |
2 |
other.release(); |
|
565 |
2 |
} |
|
566 |
|||
567 |
2512 |
inline ~EnginePointer() { reset(); } |
|
568 |
|||
569 |
2 |
inline EnginePointer& operator=(EnginePointer&& other) noexcept { |
|
570 |
✗✓ | 2 |
if (this == &other) return *this; |
571 |
2 |
this->~EnginePointer(); |
|
572 |
2 |
return *new (this) EnginePointer(std::move(other)); |
|
573 |
} |
||
574 |
|||
575 |
35 |
inline operator bool() const { return engine != nullptr; } |
|
576 |
|||
577 |
13 |
inline ENGINE* get() { return engine; } |
|
578 |
|||
579 |
2514 |
inline void reset(ENGINE* engine_ = nullptr, bool finish_on_exit_ = false) { |
|
580 |
✓✓ | 2514 |
if (engine != nullptr) { |
581 |
✗✓ | 11 |
if (finish_on_exit) { |
582 |
// This also does the equivalent of ENGINE_free. |
||
583 |
CHECK_EQ(ENGINE_finish(engine), 1); |
||
584 |
} else { |
||
585 |
✗✓ | 11 |
CHECK_EQ(ENGINE_free(engine), 1); |
586 |
} |
||
587 |
} |
||
588 |
2514 |
engine = engine_; |
|
589 |
2514 |
finish_on_exit = finish_on_exit_; |
|
590 |
2514 |
} |
|
591 |
|||
592 |
2 |
inline ENGINE* release() { |
|
593 |
2 |
ENGINE* ret = engine; |
|
594 |
2 |
engine = nullptr; |
|
595 |
2 |
finish_on_exit = false; |
|
596 |
2 |
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 |
17 |
class CipherPushContext { |
|
617 |
public: |
||
618 |
17 |
inline explicit CipherPushContext(Environment* env) : env_(env) {} |
|
619 |
|||
620 |
1583 |
inline void push_back(const char* str) { |
|
621 |
1583 |
list_.emplace_back(OneByteString(env_->isolate(), str)); |
|
622 |
1583 |
} |
|
623 |
|||
624 |
17 |
inline v8::Local<v8::Array> ToJSArray() { |
|
625 |
17 |
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*)> |
||
639 |
1931 |
void array_push_back(const TypeName* evp_ref, |
|
640 |
const char* from, |
||
641 |
const char* to, |
||
642 |
void* arg) { |
||
643 |
✗✓ | 1931 |
if (!from) |
644 |
return; |
||
645 |
|||
646 |
1931 |
const TypeName* real_instance = getbyname(from); |
|
647 |
✗✓ | 1931 |
if (!real_instance) |
648 |
return; |
||
649 |
|||
650 |
1931 |
const char* real_name = getname(real_instance); |
|
651 |
✗✓ | 1931 |
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 |
1931 |
TypeName* fetched = fetch_type(nullptr, real_name, nullptr); |
|
661 |
✓✓ | 1931 |
if (!fetched) |
662 |
348 |
return; |
|
663 |
|||
664 |
1583 |
free_type(fetched); |
|
665 |
1583 |
static_cast<CipherPushContext*>(arg)->push_back(from); |
|
666 |
} |
||
667 |
#else |
||
668 |
template <class TypeName> |
||
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 |
|||
679 |
141305 |
inline bool IsAnyByteSource(v8::Local<v8::Value> arg) { |
|
680 |
✓✓ | 150960 |
return arg->IsArrayBufferView() || |
681 |
✓✓✓✓ |
155465 |
arg->IsArrayBuffer() || |
682 |
145810 |
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 |
|||
692 |
125284 |
inline explicit ArrayBufferOrViewContents(v8::Local<v8::Value> buf) { |
|
693 |
✗✓✓✓ |
125284 |
if (buf.IsEmpty()) { |
694 |
158 |
return; |
|
695 |
} |
||
696 |
|||
697 |
✗✓✗✓ |
125126 |
CHECK(IsAnyByteSource(buf)); |
698 |
✓✓✓✓ |
125126 |
if (buf->IsArrayBufferView()) { |
699 |
120613 |
auto view = buf.As<v8::ArrayBufferView>(); |
|
700 |
120613 |
offset_ = view->ByteOffset(); |
|
701 |
120613 |
length_ = view->ByteLength(); |
|
702 |
241226 |
data_ = view->Buffer()->Data(); |
|
703 |
✓✓✓✓ |
4513 |
} else if (buf->IsArrayBuffer()) { |
704 |
4491 |
auto ab = buf.As<v8::ArrayBuffer>(); |
|
705 |
4491 |
offset_ = 0; |
|
706 |
4491 |
length_ = ab->ByteLength(); |
|
707 |
4491 |
data_ = ab->Data(); |
|
708 |
} else { |
||
709 |
22 |
auto sab = buf.As<v8::SharedArrayBuffer>(); |
|
710 |
22 |
offset_ = 0; |
|
711 |
22 |
length_ = sab->ByteLength(); |
|
712 |
22 |
data_ = sab->Data(); |
|
713 |
} |
||
714 |
} |
||
715 |
|||
716 |
18980 |
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 |
✓✓✓✓ |
18980 |
if (size() == 0) |
721 |
273 |
return &buf; |
|
722 |
18707 |
return reinterpret_cast<T*>(data_) + offset_; |
|
723 |
} |
||
724 |
|||
725 |
103310 |
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 |
✓✓✗✗ |
103310 |
if (size() == 0) |
730 |
3 |
return &buf; |
|
731 |
103307 |
return reinterpret_cast<T*>(data_) + offset_; |
|
732 |
} |
||
733 |
|||
734 |
392540 |
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. |
||
738 |
118019 |
inline bool CheckSizeInt32() { return size() <= INT_MAX; } |
|
739 |
|||
740 |
5227 |
inline ByteSource ToByteSource() const { |
|
741 |
5227 |
return ByteSource::Foreign(data(), size()); |
|
742 |
} |
||
743 |
|||
744 |
14804 |
inline ByteSource ToCopy() const { |
|
745 |
✓✓ | 14804 |
if (size() == 0) return ByteSource(); |
746 |
24208 |
ByteSource::Builder buf(size()); |
|
747 |
12104 |
memcpy(buf.data<void>(), data(), size()); |
|
748 |
12104 |
return std::move(buf).release(); |
|
749 |
} |
||
750 |
|||
751 |
95 |
inline ByteSource ToNullTerminatedCopy() const { |
|
752 |
✓✓ | 95 |
if (size() == 0) return ByteSource(); |
753 |
176 |
ByteSource::Builder buf(size() + 1); |
|
754 |
88 |
memcpy(buf.data<void>(), data(), size()); |
|
755 |
88 |
buf.data<char>()[size()] = 0; |
|
756 |
88 |
return std::move(buf).release(size()); |
|
757 |
} |
||
758 |
|||
759 |
template <typename M> |
||
760 |
104 |
void CopyTo(M* dest, size_t len) const { |
|
761 |
static_assert(sizeof(M) == 1, "sizeof(M) must equal 1"); |
||
762 |
104 |
len = std::min(len, size()); |
|
763 |
✓✗✓✗ ✓✗ |
104 |
if (len > 0 && data() != nullptr) |
764 |
104 |
memcpy(dest, data(), len); |
|
765 |
104 |
} |
|
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_ |
Generated by: GCOVR (Version 4.2) |