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 |
|
26043 |
MarkPopErrorOnReturn() { ERR_set_mark(); } |
111 |
|
26042 |
~MarkPopErrorOnReturn() { ERR_pop_to_mark(); } |
112 |
|
|
}; |
113 |
|
|
|
114 |
|
|
// Ensure that OpenSSL has enough entropy (at least 256 bits) for its PRNG. |
115 |
|
|
// The entropy pool starts out empty and needs to fill up before the PRNG |
116 |
|
|
// can be used securely. Once the pool is filled, it never dries up again; |
117 |
|
|
// its contents is stirred and reused when necessary. |
118 |
|
|
// |
119 |
|
|
// OpenSSL normally fills the pool automatically but not when someone starts |
120 |
|
|
// generating random numbers before the pool is full: in that case OpenSSL |
121 |
|
|
// keeps lowering the entropy estimate to thwart attackers trying to guess |
122 |
|
|
// the initial state of the PRNG. |
123 |
|
|
// |
124 |
|
|
// When that happens, we will have to wait until enough entropy is available. |
125 |
|
|
// That should normally never take longer than a few milliseconds. |
126 |
|
|
// |
127 |
|
|
// OpenSSL draws from /dev/random and /dev/urandom. While /dev/random may |
128 |
|
|
// block pending "true" randomness, /dev/urandom is a CSPRNG that doesn't |
129 |
|
|
// block under normal circumstances. |
130 |
|
|
// |
131 |
|
|
// The only time when /dev/urandom may conceivably block is right after boot, |
132 |
|
|
// when the whole system is still low on entropy. That's not something we can |
133 |
|
|
// do anything about. |
134 |
|
|
void CheckEntropy(); |
135 |
|
|
|
136 |
|
|
// Generate length bytes of random data. If this returns false, the data |
137 |
|
|
// may not be truly random but it's still generally good enough. |
138 |
|
|
bool EntropySource(unsigned char* buffer, size_t length); |
139 |
|
|
|
140 |
|
|
int PasswordCallback(char* buf, int size, int rwflag, void* u); |
141 |
|
|
|
142 |
|
|
int NoPasswordCallback(char* buf, int size, int rwflag, void* u); |
143 |
|
|
|
144 |
|
|
// Decode is used by the various stream-based crypto utilities to decode |
145 |
|
|
// string input. |
146 |
|
|
template <typename T> |
147 |
|
3664 |
void Decode(const v8::FunctionCallbackInfo<v8::Value>& args, |
148 |
|
|
void (*callback)(T*, const v8::FunctionCallbackInfo<v8::Value>&, |
149 |
|
|
const char*, size_t)) { |
150 |
|
|
T* ctx; |
151 |
✗✓ |
3664 |
ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder()); |
152 |
|
|
|
153 |
✓✓ |
7328 |
if (args[0]->IsString()) { |
154 |
|
1847 |
StringBytes::InlineDecoder decoder; |
155 |
|
1847 |
Environment* env = Environment::GetCurrent(args); |
156 |
|
1847 |
enum encoding enc = ParseEncoding(env->isolate(), args[1], UTF8); |
157 |
✗✓ |
5541 |
if (decoder.Decode(env, args[0].As<v8::String>(), enc).IsNothing()) |
158 |
|
|
return; |
159 |
|
1847 |
callback(ctx, args, decoder.out(), decoder.size()); |
160 |
|
|
} else { |
161 |
|
1817 |
ArrayBufferViewContents<char> buf(args[0]); |
162 |
|
1817 |
callback(ctx, args, buf.data(), buf.length()); |
163 |
|
|
} |
164 |
|
|
} |
165 |
|
|
|
166 |
|
|
#define NODE_CRYPTO_ERROR_CODES_MAP(V) \ |
167 |
|
|
V(CIPHER_JOB_FAILED, "Cipher job failed") \ |
168 |
|
|
V(DERIVING_BITS_FAILED, "Deriving bits failed") \ |
169 |
|
|
V(ENGINE_NOT_FOUND, "Engine \"%s\" was not found") \ |
170 |
|
|
V(INVALID_KEY_TYPE, "Invalid key type") \ |
171 |
|
|
V(KEY_GENERATION_JOB_FAILED, "Key generation job failed") \ |
172 |
|
|
V(OK, "Ok") \ |
173 |
|
|
|
174 |
|
|
enum class NodeCryptoError { |
175 |
|
|
#define V(CODE, DESCRIPTION) CODE, |
176 |
|
|
NODE_CRYPTO_ERROR_CODES_MAP(V) |
177 |
|
|
#undef V |
178 |
|
|
}; |
179 |
|
|
|
180 |
|
|
// Utility struct used to harvest error information from openssl's error stack |
181 |
|
|
struct CryptoErrorStore final : public MemoryRetainer { |
182 |
|
|
public: |
183 |
|
|
void Capture(); |
184 |
|
|
|
185 |
|
|
bool Empty() const; |
186 |
|
|
|
187 |
|
|
template <typename... Args> |
188 |
|
|
void Insert(const NodeCryptoError error, Args&&... args); |
189 |
|
|
|
190 |
|
|
v8::MaybeLocal<v8::Value> ToException( |
191 |
|
|
Environment* env, |
192 |
|
|
v8::Local<v8::String> exception_string = v8::Local<v8::String>()) const; |
193 |
|
|
|
194 |
|
3 |
SET_NO_MEMORY_INFO() |
195 |
|
3 |
SET_MEMORY_INFO_NAME(CryptoErrorStore) |
196 |
|
3 |
SET_SELF_SIZE(CryptoErrorStore) |
197 |
|
|
|
198 |
|
|
private: |
199 |
|
|
std::vector<std::string> errors_; |
200 |
|
|
}; |
201 |
|
|
|
202 |
|
|
template <typename... Args> |
203 |
|
14 |
void CryptoErrorStore::Insert(const NodeCryptoError error, Args&&... args) { |
204 |
|
14 |
const char* error_string = nullptr; |
205 |
✗✓✗✗ ✗✗✗ |
14 |
switch (error) { |
206 |
|
|
#define V(CODE, DESCRIPTION) \ |
207 |
|
|
case NodeCryptoError::CODE: error_string = DESCRIPTION; break; |
208 |
|
14 |
NODE_CRYPTO_ERROR_CODES_MAP(V) |
209 |
|
|
#undef V |
210 |
|
|
} |
211 |
|
14 |
errors_.emplace_back(SPrintF(error_string, |
212 |
|
|
std::forward<Args>(args)...)); |
213 |
|
14 |
} |
214 |
|
|
|
215 |
|
|
template <typename T> |
216 |
|
24840 |
T* MallocOpenSSL(size_t count) { |
217 |
|
24840 |
void* mem = OPENSSL_malloc(MultiplyWithOverflowCheck(count, sizeof(T))); |
218 |
✓✓✗✓
|
24840 |
CHECK_IMPLIES(mem == nullptr, count == 0); |
219 |
|
24840 |
return static_cast<T*>(mem); |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
// A helper class representing a read-only byte array. When deallocated, its |
223 |
|
|
// contents are zeroed. |
224 |
|
|
class ByteSource { |
225 |
|
|
public: |
226 |
|
|
class Builder { |
227 |
|
|
public: |
228 |
|
|
// Allocates memory using OpenSSL's memory allocator. |
229 |
|
23643 |
explicit Builder(size_t size) |
230 |
|
23643 |
: data_(MallocOpenSSL<char>(size)), size_(size) {} |
231 |
|
|
|
232 |
|
|
Builder(Builder&& other) = delete; |
233 |
|
|
Builder& operator=(Builder&& other) = delete; |
234 |
|
|
Builder(const Builder&) = delete; |
235 |
|
|
Builder& operator=(const Builder&) = delete; |
236 |
|
|
|
237 |
|
23643 |
~Builder() { OPENSSL_clear_free(data_, size_); } |
238 |
|
|
|
239 |
|
|
// Returns the underlying non-const pointer. |
240 |
|
|
template <typename T> |
241 |
|
51184 |
T* data() { |
242 |
|
51184 |
return reinterpret_cast<T*>(data_); |
243 |
|
|
} |
244 |
|
|
|
245 |
|
|
// Returns the (allocated) size in bytes. |
246 |
|
13 |
size_t size() const { return size_; } |
247 |
|
|
|
248 |
|
|
// Finalizes the Builder and returns a read-only view that is optionally |
249 |
|
|
// truncated. |
250 |
|
23555 |
ByteSource release(std::optional<size_t> resize = std::nullopt) && { |
251 |
✓✓ |
23555 |
if (resize) { |
252 |
✗✓ |
4683 |
CHECK_LE(*resize, size_); |
253 |
✓✓ |
4683 |
if (*resize == 0) { |
254 |
|
1 |
OPENSSL_clear_free(data_, size_); |
255 |
|
1 |
data_ = nullptr; |
256 |
|
|
} |
257 |
|
4683 |
size_ = *resize; |
258 |
|
|
} |
259 |
|
23555 |
ByteSource out = ByteSource::Allocated(data_, size_); |
260 |
|
23555 |
data_ = nullptr; |
261 |
|
23555 |
size_ = 0; |
262 |
|
23555 |
return out; |
263 |
|
|
} |
264 |
|
|
|
265 |
|
|
private: |
266 |
|
|
void* data_; |
267 |
|
|
size_t size_; |
268 |
|
|
}; |
269 |
|
|
|
270 |
|
33680 |
ByteSource() = default; |
271 |
|
|
ByteSource(ByteSource&& other) noexcept; |
272 |
|
|
~ByteSource(); |
273 |
|
|
|
274 |
|
|
ByteSource& operator=(ByteSource&& other) noexcept; |
275 |
|
|
|
276 |
|
|
ByteSource(const ByteSource&) = delete; |
277 |
|
|
ByteSource& operator=(const ByteSource&) = delete; |
278 |
|
|
|
279 |
|
|
template <typename T = void> |
280 |
|
61176 |
const T* data() const { |
281 |
|
61176 |
return reinterpret_cast<const T*>(data_); |
282 |
|
|
} |
283 |
|
|
|
284 |
|
37797 |
size_t size() const { return size_; } |
285 |
|
|
|
286 |
|
2714 |
operator bool() const { return data_ != nullptr; } |
287 |
|
|
|
288 |
|
2841 |
BignumPointer ToBN() const { |
289 |
|
2841 |
return BignumPointer(BN_bin2bn(data<unsigned char>(), size(), nullptr)); |
290 |
|
|
} |
291 |
|
|
|
292 |
|
|
// Creates a v8::BackingStore that takes over responsibility for |
293 |
|
|
// any allocated data. The ByteSource will be reset with size = 0 |
294 |
|
|
// after being called. |
295 |
|
|
std::unique_ptr<v8::BackingStore> ReleaseToBackingStore(); |
296 |
|
|
|
297 |
|
|
v8::Local<v8::ArrayBuffer> ToArrayBuffer(Environment* env); |
298 |
|
|
|
299 |
|
|
v8::MaybeLocal<v8::Uint8Array> ToBuffer(Environment* env); |
300 |
|
|
|
301 |
|
|
static ByteSource Allocated(void* data, size_t size); |
302 |
|
|
static ByteSource Foreign(const void* data, size_t size); |
303 |
|
|
|
304 |
|
|
static ByteSource FromEncodedString(Environment* env, |
305 |
|
|
v8::Local<v8::String> value, |
306 |
|
|
enum encoding enc = BASE64); |
307 |
|
|
|
308 |
|
|
static ByteSource FromStringOrBuffer(Environment* env, |
309 |
|
|
v8::Local<v8::Value> value); |
310 |
|
|
|
311 |
|
|
static ByteSource FromString(Environment* env, |
312 |
|
|
v8::Local<v8::String> str, |
313 |
|
|
bool ntc = false); |
314 |
|
|
|
315 |
|
|
static ByteSource FromBuffer(v8::Local<v8::Value> buffer, |
316 |
|
|
bool ntc = false); |
317 |
|
|
|
318 |
|
|
static ByteSource FromBIO(const BIOPointer& bio); |
319 |
|
|
|
320 |
|
|
static ByteSource NullTerminatedCopy(Environment* env, |
321 |
|
|
v8::Local<v8::Value> value); |
322 |
|
|
|
323 |
|
|
static ByteSource FromSymmetricKeyObjectHandle(v8::Local<v8::Value> handle); |
324 |
|
|
|
325 |
|
|
static ByteSource FromSecretKeyBytes( |
326 |
|
|
Environment* env, v8::Local<v8::Value> value); |
327 |
|
|
|
328 |
|
|
private: |
329 |
|
|
const void* data_ = nullptr; |
330 |
|
|
void* allocated_data_ = nullptr; |
331 |
|
|
size_t size_ = 0; |
332 |
|
|
|
333 |
|
31346 |
ByteSource(const void* data, void* allocated_data, size_t size) |
334 |
|
31346 |
: data_(data), allocated_data_(allocated_data), size_(size) {} |
335 |
|
|
}; |
336 |
|
|
|
337 |
|
|
enum CryptoJobMode { |
338 |
|
|
kCryptoJobAsync, |
339 |
|
|
kCryptoJobSync |
340 |
|
|
}; |
341 |
|
|
|
342 |
|
|
CryptoJobMode GetCryptoJobMode(v8::Local<v8::Value> args); |
343 |
|
|
|
344 |
|
|
template <typename CryptoJobTraits> |
345 |
|
|
class CryptoJob : public AsyncWrap, public ThreadPoolWork { |
346 |
|
|
public: |
347 |
|
|
using AdditionalParams = typename CryptoJobTraits::AdditionalParameters; |
348 |
|
|
|
349 |
|
16046 |
explicit CryptoJob( |
350 |
|
|
Environment* env, |
351 |
|
|
v8::Local<v8::Object> object, |
352 |
|
|
AsyncWrap::ProviderType type, |
353 |
|
|
CryptoJobMode mode, |
354 |
|
|
AdditionalParams&& params) |
355 |
|
|
: AsyncWrap(env, object, type), |
356 |
|
|
ThreadPoolWork(env), |
357 |
|
|
mode_(mode), |
358 |
|
16046 |
params_(std::move(params)) { |
359 |
|
|
// If the CryptoJob is async, then the instance will be |
360 |
|
|
// cleaned up when AfterThreadPoolWork is called. |
361 |
✓✓ |
16046 |
if (mode == kCryptoJobSync) MakeWeak(); |
362 |
|
16046 |
} |
363 |
|
|
|
364 |
|
|
bool IsNotIndicativeOfMemoryLeakAtExit() const override { |
365 |
|
|
// CryptoJobs run a work in the libuv thread pool and may still |
366 |
|
|
// exist when the event loop empties and starts to exit. |
367 |
|
|
return true; |
368 |
|
|
} |
369 |
|
|
|
370 |
|
14211 |
void AfterThreadPoolWork(int status) override { |
371 |
|
14211 |
Environment* env = AsyncWrap::env(); |
372 |
✗✓ |
14211 |
CHECK_EQ(mode_, kCryptoJobAsync); |
373 |
✗✓✗✗
|
14211 |
CHECK(status == 0 || status == UV_ECANCELED); |
374 |
|
14211 |
std::unique_ptr<CryptoJob> ptr(this); |
375 |
|
|
// If the job was canceled do not execute the callback. |
376 |
|
|
// TODO(@jasnell): We should likely revisit skipping the |
377 |
|
|
// callback on cancel as that could leave the JS in a pending |
378 |
|
|
// state (e.g. unresolved promises...) |
379 |
✗✓ |
14211 |
if (status == UV_ECANCELED) return; |
380 |
|
14211 |
v8::HandleScope handle_scope(env->isolate()); |
381 |
|
28422 |
v8::Context::Scope context_scope(env->context()); |
382 |
|
|
|
383 |
|
|
// TODO(tniessen): Remove the exception handling logic here as soon as we |
384 |
|
|
// can verify that no code path in ToResult will ever throw an exception. |
385 |
|
|
v8::Local<v8::Value> exception; |
386 |
✓✓ |
42633 |
v8::Local<v8::Value> args[2]; |
387 |
|
|
{ |
388 |
|
14211 |
node::errors::TryCatchScope try_catch(env); |
389 |
|
14211 |
v8::Maybe<bool> ret = ptr->ToResult(&args[0], &args[1]); |
390 |
✓✓ |
14211 |
if (!ret.IsJust()) { |
391 |
✗✓ |
4 |
CHECK(try_catch.HasCaught()); |
392 |
|
4 |
exception = try_catch.Exception(); |
393 |
✗✓ |
14207 |
} else if (!ret.FromJust()) { |
394 |
|
|
return; |
395 |
|
|
} |
396 |
|
|
} |
397 |
|
|
|
398 |
✓✓ |
14211 |
if (exception.IsEmpty()) { |
399 |
|
14207 |
ptr->MakeCallback(env->ondone_string(), arraysize(args), args); |
400 |
|
|
} else { |
401 |
|
4 |
ptr->MakeCallback(env->ondone_string(), 1, &exception); |
402 |
|
|
} |
403 |
|
|
} |
404 |
|
|
|
405 |
|
|
virtual v8::Maybe<bool> ToResult( |
406 |
|
|
v8::Local<v8::Value>* err, |
407 |
|
|
v8::Local<v8::Value>* result) = 0; |
408 |
|
|
|
409 |
|
16036 |
CryptoJobMode mode() const { return mode_; } |
410 |
|
|
|
411 |
|
16299 |
CryptoErrorStore* errors() { return &errors_; } |
412 |
|
|
|
413 |
|
29275 |
AdditionalParams* params() { return ¶ms_; } |
414 |
|
|
|
415 |
|
6 |
std::string MemoryInfoName() const override { |
416 |
|
6 |
return CryptoJobTraits::JobName; |
417 |
|
|
} |
418 |
|
|
|
419 |
|
6 |
void MemoryInfo(MemoryTracker* tracker) const override { |
420 |
|
6 |
tracker->TrackField("params", params_); |
421 |
|
6 |
tracker->TrackField("errors", errors_); |
422 |
|
|
} |
423 |
|
|
|
424 |
|
16036 |
static void Run(const v8::FunctionCallbackInfo<v8::Value>& args) { |
425 |
|
16036 |
Environment* env = Environment::GetCurrent(args); |
426 |
|
|
|
427 |
|
|
CryptoJob<CryptoJobTraits>* job; |
428 |
✗✓ |
30249 |
ASSIGN_OR_RETURN_UNWRAP(&job, args.Holder()); |
429 |
✓✓ |
16036 |
if (job->mode() == kCryptoJobAsync) |
430 |
|
14213 |
return job->ScheduleWork(); |
431 |
|
|
|
432 |
✓✓ |
5469 |
v8::Local<v8::Value> ret[2]; |
433 |
|
1823 |
env->PrintSyncTrace(); |
434 |
|
1823 |
job->DoThreadPoolWork(); |
435 |
|
1823 |
v8::Maybe<bool> result = job->ToResult(&ret[0], &ret[1]); |
436 |
✓✓✓✗ ✓✓ |
3640 |
if (result.IsJust() && result.FromJust()) { |
437 |
|
3634 |
args.GetReturnValue().Set( |
438 |
|
|
v8::Array::New(env->isolate(), ret, arraysize(ret))); |
439 |
|
|
} |
440 |
|
|
} |
441 |
|
|
|
442 |
|
32550 |
static void Initialize( |
443 |
|
|
v8::FunctionCallback new_fn, |
444 |
|
|
Environment* env, |
445 |
|
|
v8::Local<v8::Object> target) { |
446 |
|
32550 |
v8::Isolate* isolate = env->isolate(); |
447 |
|
65100 |
v8::HandleScope scope(isolate); |
448 |
|
32550 |
v8::Local<v8::Context> context = env->context(); |
449 |
|
32550 |
v8::Local<v8::FunctionTemplate> job = NewFunctionTemplate(isolate, new_fn); |
450 |
|
32550 |
job->Inherit(AsyncWrap::GetConstructorTemplate(env)); |
451 |
|
65100 |
job->InstanceTemplate()->SetInternalFieldCount( |
452 |
|
|
AsyncWrap::kInternalFieldCount); |
453 |
|
32550 |
SetProtoMethod(isolate, job, "run", Run); |
454 |
|
32550 |
SetConstructorFunction(context, target, CryptoJobTraits::JobName, job); |
455 |
|
32550 |
} |
456 |
|
|
|
457 |
|
224994 |
static void RegisterExternalReferences(v8::FunctionCallback new_fn, |
458 |
|
|
ExternalReferenceRegistry* registry) { |
459 |
|
224994 |
registry->Register(new_fn); |
460 |
|
224994 |
registry->Register(Run); |
461 |
|
224994 |
} |
462 |
|
|
|
463 |
|
|
private: |
464 |
|
|
const CryptoJobMode mode_; |
465 |
|
|
CryptoErrorStore errors_; |
466 |
|
|
AdditionalParams params_; |
467 |
|
|
}; |
468 |
|
|
|
469 |
|
|
template <typename DeriveBitsTraits> |
470 |
|
|
class DeriveBitsJob final : public CryptoJob<DeriveBitsTraits> { |
471 |
|
|
public: |
472 |
|
|
using AdditionalParams = typename DeriveBitsTraits::AdditionalParameters; |
473 |
|
|
|
474 |
|
9264 |
static void New(const v8::FunctionCallbackInfo<v8::Value>& args) { |
475 |
|
9264 |
Environment* env = Environment::GetCurrent(args); |
476 |
|
|
|
477 |
|
9264 |
CryptoJobMode mode = GetCryptoJobMode(args[0]); |
478 |
|
|
|
479 |
|
9264 |
AdditionalParams params; |
480 |
✓✓ |
18528 |
if (DeriveBitsTraits::AdditionalConfig(mode, args, 1, ¶ms) |
481 |
|
|
.IsNothing()) { |
482 |
|
|
// The DeriveBitsTraits::AdditionalConfig is responsible for |
483 |
|
|
// calling an appropriate THROW_CRYPTO_* variant reporting |
484 |
|
|
// whatever error caused initialization to fail. |
485 |
|
61 |
return; |
486 |
|
|
} |
487 |
|
|
|
488 |
|
9203 |
new DeriveBitsJob(env, args.This(), mode, std::move(params)); |
489 |
|
|
} |
490 |
|
|
|
491 |
|
13175 |
static void Initialize( |
492 |
|
|
Environment* env, |
493 |
|
|
v8::Local<v8::Object> target) { |
494 |
|
13175 |
CryptoJob<DeriveBitsTraits>::Initialize(New, env, target); |
495 |
|
13175 |
} |
496 |
|
|
|
497 |
|
91069 |
static void RegisterExternalReferences(ExternalReferenceRegistry* registry) { |
498 |
|
91069 |
CryptoJob<DeriveBitsTraits>::RegisterExternalReferences(New, registry); |
499 |
|
91069 |
} |
500 |
|
|
|
501 |
|
9203 |
DeriveBitsJob( |
502 |
|
|
Environment* env, |
503 |
|
|
v8::Local<v8::Object> object, |
504 |
|
|
CryptoJobMode mode, |
505 |
|
|
AdditionalParams&& params) |
506 |
|
|
: CryptoJob<DeriveBitsTraits>( |
507 |
|
|
env, |
508 |
|
|
object, |
509 |
|
|
DeriveBitsTraits::Provider, |
510 |
|
|
mode, |
511 |
|
9203 |
std::move(params)) {} |
512 |
|
|
|
513 |
|
9203 |
void DoThreadPoolWork() override { |
514 |
✓✓ |
9203 |
if (!DeriveBitsTraits::DeriveBits( |
515 |
|
|
AsyncWrap::env(), |
516 |
|
9203 |
*CryptoJob<DeriveBitsTraits>::params(), &out_)) { |
517 |
|
14 |
CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors(); |
518 |
|
14 |
errors->Capture(); |
519 |
✓✗ |
14 |
if (errors->Empty()) |
520 |
|
14 |
errors->Insert(NodeCryptoError::DERIVING_BITS_FAILED); |
521 |
|
14 |
return; |
522 |
|
|
} |
523 |
|
9189 |
success_ = true; |
524 |
|
|
} |
525 |
|
|
|
526 |
|
9203 |
v8::Maybe<bool> ToResult( |
527 |
|
|
v8::Local<v8::Value>* err, |
528 |
|
|
v8::Local<v8::Value>* result) override { |
529 |
|
9203 |
Environment* env = AsyncWrap::env(); |
530 |
|
9203 |
CryptoErrorStore* errors = CryptoJob<DeriveBitsTraits>::errors(); |
531 |
✓✓ |
9203 |
if (success_) { |
532 |
✗✓ |
9189 |
CHECK(errors->Empty()); |
533 |
|
9189 |
*err = v8::Undefined(env->isolate()); |
534 |
|
9189 |
return DeriveBitsTraits::EncodeOutput( |
535 |
|
|
env, |
536 |
|
9189 |
*CryptoJob<DeriveBitsTraits>::params(), |
537 |
|
|
&out_, |
538 |
|
9189 |
result); |
539 |
|
|
} |
540 |
|
|
|
541 |
✗✓ |
14 |
if (errors->Empty()) |
542 |
|
|
errors->Capture(); |
543 |
✗✓ |
14 |
CHECK(!errors->Empty()); |
544 |
|
28 |
*result = v8::Undefined(env->isolate()); |
545 |
|
28 |
return v8::Just(errors->ToException(env).ToLocal(err)); |
546 |
|
|
} |
547 |
|
|
|
548 |
|
6 |
SET_SELF_SIZE(DeriveBitsJob) |
549 |
|
3 |
void MemoryInfo(MemoryTracker* tracker) const override { |
550 |
|
6 |
tracker->TrackFieldWithSize("out", out_.size()); |
551 |
|
6 |
CryptoJob<DeriveBitsTraits>::MemoryInfo(tracker); |
552 |
|
|
} |
553 |
|
|
|
554 |
|
|
private: |
555 |
|
|
ByteSource out_; |
556 |
|
|
bool success_ = false; |
557 |
|
|
}; |
558 |
|
|
|
559 |
|
|
void ThrowCryptoError(Environment* env, |
560 |
|
|
unsigned long err, // NOLINT(runtime/int) |
561 |
|
|
const char* message = nullptr); |
562 |
|
|
|
563 |
|
|
#ifndef OPENSSL_NO_ENGINE |
564 |
|
|
struct EnginePointer { |
565 |
|
|
ENGINE* engine = nullptr; |
566 |
|
|
bool finish_on_exit = false; |
567 |
|
|
|
568 |
|
2499 |
inline EnginePointer() = default; |
569 |
|
|
|
570 |
|
13 |
inline explicit EnginePointer(ENGINE* engine_, bool finish_on_exit_ = false) |
571 |
|
13 |
: engine(engine_), |
572 |
|
13 |
finish_on_exit(finish_on_exit_) {} |
573 |
|
|
|
574 |
|
2 |
inline EnginePointer(EnginePointer&& other) noexcept |
575 |
|
2 |
: engine(other.engine), |
576 |
|
2 |
finish_on_exit(other.finish_on_exit) { |
577 |
|
2 |
other.release(); |
578 |
|
2 |
} |
579 |
|
|
|
580 |
|
2505 |
inline ~EnginePointer() { reset(); } |
581 |
|
|
|
582 |
|
2 |
inline EnginePointer& operator=(EnginePointer&& other) noexcept { |
583 |
✗✓ |
2 |
if (this == &other) return *this; |
584 |
|
2 |
this->~EnginePointer(); |
585 |
|
2 |
return *new (this) EnginePointer(std::move(other)); |
586 |
|
|
} |
587 |
|
|
|
588 |
|
35 |
inline operator bool() const { return engine != nullptr; } |
589 |
|
|
|
590 |
|
13 |
inline ENGINE* get() { return engine; } |
591 |
|
|
|
592 |
|
2507 |
inline void reset(ENGINE* engine_ = nullptr, bool finish_on_exit_ = false) { |
593 |
✓✓ |
2507 |
if (engine != nullptr) { |
594 |
✗✓ |
11 |
if (finish_on_exit) { |
595 |
|
|
// This also does the equivalent of ENGINE_free. |
596 |
|
|
CHECK_EQ(ENGINE_finish(engine), 1); |
597 |
|
|
} else { |
598 |
✗✓ |
11 |
CHECK_EQ(ENGINE_free(engine), 1); |
599 |
|
|
} |
600 |
|
|
} |
601 |
|
2507 |
engine = engine_; |
602 |
|
2507 |
finish_on_exit = finish_on_exit_; |
603 |
|
2507 |
} |
604 |
|
|
|
605 |
|
2 |
inline ENGINE* release() { |
606 |
|
2 |
ENGINE* ret = engine; |
607 |
|
2 |
engine = nullptr; |
608 |
|
2 |
finish_on_exit = false; |
609 |
|
2 |
return ret; |
610 |
|
|
} |
611 |
|
|
}; |
612 |
|
|
|
613 |
|
|
EnginePointer LoadEngineById(const char* id, CryptoErrorStore* errors); |
614 |
|
|
|
615 |
|
|
bool SetEngine( |
616 |
|
|
const char* id, |
617 |
|
|
uint32_t flags, |
618 |
|
|
CryptoErrorStore* errors = nullptr); |
619 |
|
|
|
620 |
|
|
void SetEngine(const v8::FunctionCallbackInfo<v8::Value>& args); |
621 |
|
|
#endif // !OPENSSL_NO_ENGINE |
622 |
|
|
|
623 |
|
|
void GetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args); |
624 |
|
|
|
625 |
|
|
void SetFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args); |
626 |
|
|
|
627 |
|
|
void TestFipsCrypto(const v8::FunctionCallbackInfo<v8::Value>& args); |
628 |
|
|
|
629 |
|
|
class CipherPushContext { |
630 |
|
|
public: |
631 |
|
7 |
inline explicit CipherPushContext(Environment* env) : env_(env) {} |
632 |
|
|
|
633 |
|
581 |
inline void push_back(const char* str) { |
634 |
|
581 |
list_.emplace_back(OneByteString(env_->isolate(), str)); |
635 |
|
581 |
} |
636 |
|
|
|
637 |
|
7 |
inline v8::Local<v8::Array> ToJSArray() { |
638 |
|
7 |
return v8::Array::New(env_->isolate(), list_.data(), list_.size()); |
639 |
|
|
} |
640 |
|
|
|
641 |
|
|
private: |
642 |
|
|
std::vector<v8::Local<v8::Value>> list_; |
643 |
|
|
Environment* env_; |
644 |
|
|
}; |
645 |
|
|
|
646 |
|
|
#if OPENSSL_VERSION_MAJOR >= 3 |
647 |
|
|
template <class TypeName, |
648 |
|
|
TypeName* fetch_type(OSSL_LIB_CTX*, const char*, const char*), |
649 |
|
|
void free_type(TypeName*), |
650 |
|
|
const TypeName* getbyname(const char*), |
651 |
|
|
const char* getname(const TypeName*)> |
652 |
|
761 |
void array_push_back(const TypeName* evp_ref, |
653 |
|
|
const char* from, |
654 |
|
|
const char* to, |
655 |
|
|
void* arg) { |
656 |
✗✓ |
761 |
if (!from) |
657 |
|
|
return; |
658 |
|
|
|
659 |
|
761 |
const TypeName* real_instance = getbyname(from); |
660 |
✗✓ |
761 |
if (!real_instance) |
661 |
|
|
return; |
662 |
|
|
|
663 |
|
761 |
const char* real_name = getname(real_instance); |
664 |
✗✓ |
761 |
if (!real_name) |
665 |
|
|
return; |
666 |
|
|
|
667 |
|
|
// EVP_*_fetch() does not support alias names, so we need to pass it the |
668 |
|
|
// real/original algorithm name. |
669 |
|
|
// We use EVP_*_fetch() as a filter here because it will only return an |
670 |
|
|
// instance if the algorithm is supported by the public OpenSSL APIs (some |
671 |
|
|
// algorithms are used internally by OpenSSL and are also passed to this |
672 |
|
|
// callback). |
673 |
|
761 |
TypeName* fetched = fetch_type(nullptr, real_name, nullptr); |
674 |
✓✓ |
761 |
if (!fetched) |
675 |
|
180 |
return; |
676 |
|
|
|
677 |
|
581 |
free_type(fetched); |
678 |
|
581 |
static_cast<CipherPushContext*>(arg)->push_back(from); |
679 |
|
|
} |
680 |
|
|
#else |
681 |
|
|
template <class TypeName> |
682 |
|
|
void array_push_back(const TypeName* evp_ref, |
683 |
|
|
const char* from, |
684 |
|
|
const char* to, |
685 |
|
|
void* arg) { |
686 |
|
|
if (!from) |
687 |
|
|
return; |
688 |
|
|
static_cast<CipherPushContext*>(arg)->push_back(from); |
689 |
|
|
} |
690 |
|
|
#endif |
691 |
|
|
|
692 |
|
141287 |
inline bool IsAnyByteSource(v8::Local<v8::Value> arg) { |
693 |
✓✓ |
150936 |
return arg->IsArrayBufferView() || |
694 |
✓✓✓✓
|
160585 |
arg->IsArrayBuffer() || |
695 |
|
145792 |
arg->IsSharedArrayBuffer(); |
696 |
|
|
} |
697 |
|
|
|
698 |
|
|
template <typename T> |
699 |
|
|
class ArrayBufferOrViewContents { |
700 |
|
|
public: |
701 |
|
|
ArrayBufferOrViewContents() = default; |
702 |
|
|
ArrayBufferOrViewContents(const ArrayBufferOrViewContents&) = delete; |
703 |
|
|
void operator=(const ArrayBufferOrViewContents&) = delete; |
704 |
|
|
|
705 |
|
227829 |
inline explicit ArrayBufferOrViewContents(v8::Local<v8::Value> buf) { |
706 |
✓✓ |
227829 |
if (buf.IsEmpty()) { |
707 |
|
316 |
return; |
708 |
|
|
} |
709 |
|
|
|
710 |
✗✓ |
227513 |
CHECK(IsAnyByteSource(buf)); |
711 |
✓✓ |
227513 |
if (buf->IsArrayBufferView()) { |
712 |
|
222633 |
auto view = buf.As<v8::ArrayBufferView>(); |
713 |
|
222633 |
offset_ = view->ByteOffset(); |
714 |
|
222633 |
length_ = view->ByteLength(); |
715 |
|
445266 |
data_ = view->Buffer()->Data(); |
716 |
✓✓ |
4880 |
} else if (buf->IsArrayBuffer()) { |
717 |
|
4856 |
auto ab = buf.As<v8::ArrayBuffer>(); |
718 |
|
4856 |
offset_ = 0; |
719 |
|
4856 |
length_ = ab->ByteLength(); |
720 |
|
4856 |
data_ = ab->Data(); |
721 |
|
|
} else { |
722 |
|
24 |
auto sab = buf.As<v8::SharedArrayBuffer>(); |
723 |
|
24 |
offset_ = 0; |
724 |
|
24 |
length_ = sab->ByteLength(); |
725 |
|
24 |
data_ = sab->Data(); |
726 |
|
|
} |
727 |
|
|
} |
728 |
|
|
|
729 |
|
20166 |
inline const T* data() const { |
730 |
|
|
// Ideally, these would return nullptr if IsEmpty() or length_ is zero, |
731 |
|
|
// but some of the openssl API react badly if given a nullptr even when |
732 |
|
|
// length is zero, so we have to return something. |
733 |
✓✓ |
20166 |
if (size() == 0) |
734 |
|
149 |
return &buf; |
735 |
|
20017 |
return reinterpret_cast<T*>(data_) + offset_; |
736 |
|
|
} |
737 |
|
|
|
738 |
|
103308 |
inline T* data() { |
739 |
|
|
// Ideally, these would return nullptr if IsEmpty() or length_ is zero, |
740 |
|
|
// but some of the openssl API react badly if given a nullptr even when |
741 |
|
|
// length is zero, so we have to return something. |
742 |
✓✓ |
103308 |
if (size() == 0) |
743 |
|
3 |
return &buf; |
744 |
|
103305 |
return reinterpret_cast<T*>(data_) + offset_; |
745 |
|
|
} |
746 |
|
|
|
747 |
|
700851 |
inline size_t size() const { return length_; } |
748 |
|
|
|
749 |
|
|
// In most cases, input buffer sizes passed in to openssl need to |
750 |
|
|
// be limited to <= INT_MAX. This utility method helps us check. |
751 |
|
220025 |
inline bool CheckSizeInt32() { return size() <= INT_MAX; } |
752 |
|
|
|
753 |
|
5072 |
inline ByteSource ToByteSource() const { |
754 |
|
5072 |
return ByteSource::Foreign(data(), size()); |
755 |
|
|
} |
756 |
|
|
|
757 |
|
14790 |
inline ByteSource ToCopy() const { |
758 |
✓✓ |
14790 |
if (size() == 0) return ByteSource(); |
759 |
|
12102 |
ByteSource::Builder buf(size()); |
760 |
|
12102 |
memcpy(buf.data<void>(), data(), size()); |
761 |
|
12102 |
return std::move(buf).release(); |
762 |
|
|
} |
763 |
|
|
|
764 |
|
95 |
inline ByteSource ToNullTerminatedCopy() const { |
765 |
✓✓ |
95 |
if (size() == 0) return ByteSource(); |
766 |
|
88 |
ByteSource::Builder buf(size() + 1); |
767 |
|
88 |
memcpy(buf.data<void>(), data(), size()); |
768 |
|
88 |
buf.data<char>()[size()] = 0; |
769 |
|
88 |
return std::move(buf).release(size()); |
770 |
|
|
} |
771 |
|
|
|
772 |
|
|
template <typename M> |
773 |
|
104 |
void CopyTo(M* dest, size_t len) const { |
774 |
|
|
static_assert(sizeof(M) == 1, "sizeof(M) must equal 1"); |
775 |
|
104 |
len = std::min(len, size()); |
776 |
✓✗✓✗ ✓✗ |
104 |
if (len > 0 && data() != nullptr) |
777 |
|
104 |
memcpy(dest, data(), len); |
778 |
|
104 |
} |
779 |
|
|
|
780 |
|
|
private: |
781 |
|
|
T buf = 0; |
782 |
|
|
size_t offset_ = 0; |
783 |
|
|
size_t length_ = 0; |
784 |
|
|
void* data_ = nullptr; |
785 |
|
|
|
786 |
|
|
// Declaring operator new and delete as deleted is not spec compliant. |
787 |
|
|
// Therefore declare them private instead to disable dynamic alloc |
788 |
|
|
void* operator new(size_t); |
789 |
|
|
void* operator new[](size_t); |
790 |
|
|
void operator delete(void*); |
791 |
|
|
void operator delete[](void*); |
792 |
|
|
}; |
793 |
|
|
|
794 |
|
|
v8::MaybeLocal<v8::Value> EncodeBignum( |
795 |
|
|
Environment* env, |
796 |
|
|
const BIGNUM* bn, |
797 |
|
|
int size, |
798 |
|
|
v8::Local<v8::Value>* error); |
799 |
|
|
|
800 |
|
|
v8::Maybe<bool> SetEncodedValue( |
801 |
|
|
Environment* env, |
802 |
|
|
v8::Local<v8::Object> target, |
803 |
|
|
v8::Local<v8::String> name, |
804 |
|
|
const BIGNUM* bn, |
805 |
|
|
int size = 0); |
806 |
|
|
|
807 |
|
|
namespace Util { |
808 |
|
|
void Initialize(Environment* env, v8::Local<v8::Object> target); |
809 |
|
|
void RegisterExternalReferences(ExternalReferenceRegistry* registry); |
810 |
|
|
} // namespace Util |
811 |
|
|
|
812 |
|
|
} // namespace crypto |
813 |
|
|
} // namespace node |
814 |
|
|
|
815 |
|
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
816 |
|
|
#endif // SRC_CRYPTO_CRYPTO_UTIL_H_ |