Bug Summary

File:out/../src/crypto/crypto_keys.h
Warning:line 65, column 8
Value assigned to field 'cipher_' in implicit constructor is garbage or undefined

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name crypto_keys.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/maurizio/node-v18.6.0/out -resource-dir /usr/local/lib/clang/16.0.0 -D V8_DEPRECATION_WARNINGS -D V8_IMMINENT_DEPRECATION_WARNINGS -D _GLIBCXX_USE_CXX11_ABI=1 -D NODE_OPENSSL_CONF_NAME=nodejs_conf -D NODE_OPENSSL_HAS_QUIC -D __STDC_FORMAT_MACROS -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D NODE_ARCH="x64" -D NODE_PLATFORM="linux" -D NODE_WANT_INTERNALS=1 -D V8_DEPRECATION_WARNINGS=1 -D NODE_OPENSSL_SYSTEM_CERT_PATH="" -D NODE_USE_NODE_CODE_CACHE=1 -D HAVE_INSPECTOR=1 -D NODE_ENABLE_LARGE_CODE_PAGES=1 -D __POSIX__ -D NODE_USE_V8_PLATFORM=1 -D NODE_HAVE_I18N_SUPPORT=1 -D HAVE_OPENSSL=1 -D OPENSSL_API_COMPAT=0x10100000L -D UCONFIG_NO_SERVICE=1 -D U_ENABLE_DYLOAD=0 -D U_STATIC_IMPLEMENTATION=1 -D U_HAVE_STD_STRING=1 -D UCONFIG_NO_BREAK_ITERATION=0 -D _LARGEFILE_SOURCE -D _FILE_OFFSET_BITS=64 -D _POSIX_C_SOURCE=200112 -D NGHTTP2_STATICLIB -D NDEBUG -D OPENSSL_USE_NODELETE -D L_ENDIAN -D OPENSSL_BUILDING_OPENSSL -D AES_ASM -D BSAES_ASM -D CMLL_ASM -D ECP_NISTZ256_ASM -D GHASH_ASM -D KECCAK1600_ASM -D MD5_ASM -D OPENSSL_BN_ASM_GF2m -D OPENSSL_BN_ASM_MONT -D OPENSSL_BN_ASM_MONT5 -D OPENSSL_CPUID_OBJ -D OPENSSL_IA32_SSE2 -D PADLOCK_ASM -D POLY1305_ASM -D SHA1_ASM -D SHA256_ASM -D SHA512_ASM -D VPAES_ASM -D WHIRLPOOL_ASM -D X25519_ASM -D OPENSSL_PIC -D NGTCP2_STATICLIB -D NGHTTP3_STATICLIB -I ../src -I /home/maurizio/node-v18.6.0/out/Release/obj/gen -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/include -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/src -I ../deps/googletest/include -I ../deps/histogram/src -I ../deps/uvwasi/include -I ../deps/v8/include -I ../deps/icu-small/source/i18n -I ../deps/icu-small/source/common -I ../deps/zlib -I ../deps/llhttp/include -I ../deps/cares/include -I ../deps/uv/include -I ../deps/nghttp2/lib/includes -I ../deps/brotli/c/include -I ../deps/openssl/openssl/include -I ../deps/openssl/openssl/crypto/include -I ../deps/openssl/config/archs/linux-x86_64/asm/include -I ../deps/openssl/config/archs/linux-x86_64/asm -I ../deps/ngtcp2 -I ../deps/ngtcp2/ngtcp2/lib/includes -I ../deps/ngtcp2/ngtcp2/crypto/includes -I ../deps/ngtcp2/nghttp3/lib/includes -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward -internal-isystem /usr/local/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-unused-parameter -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/home/maurizio/node-v18.6.0/out -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-08-22-142216-507842-1 -x c++ ../src/crypto/crypto_keys.cc

../src/crypto/crypto_keys.cc

1#include "crypto/crypto_keys.h"
2#include "crypto/crypto_common.h"
3#include "crypto/crypto_dsa.h"
4#include "crypto/crypto_ec.h"
5#include "crypto/crypto_dh.h"
6#include "crypto/crypto_rsa.h"
7#include "crypto/crypto_util.h"
8#include "async_wrap-inl.h"
9#include "base_object-inl.h"
10#include "env-inl.h"
11#include "memory_tracker-inl.h"
12#include "node.h"
13#include "node_buffer.h"
14#include "string_bytes.h"
15#include "threadpoolwork-inl.h"
16#include "util-inl.h"
17#include "v8.h"
18
19namespace node {
20
21using v8::Array;
22using v8::Context;
23using v8::Function;
24using v8::FunctionCallbackInfo;
25using v8::FunctionTemplate;
26using v8::Int32;
27using v8::Just;
28using v8::Local;
29using v8::Maybe;
30using v8::MaybeLocal;
31using v8::NewStringType;
32using v8::Nothing;
33using v8::Number;
34using v8::Object;
35using v8::String;
36using v8::Uint32;
37using v8::Undefined;
38using v8::Value;
39
40namespace crypto {
41namespace {
42void GetKeyFormatAndTypeFromJs(
43 AsymmetricKeyEncodingConfig* config,
44 const FunctionCallbackInfo<Value>& args,
45 unsigned int* offset,
46 KeyEncodingContext context) {
47 // During key pair generation, it is possible not to specify a key encoding,
48 // which will lead to a key object being returned.
49 if (args[*offset]->IsUndefined()) {
50 CHECK_EQ(context, kKeyContextGenerate)do { if (__builtin_expect(!!(!((context) == (kKeyContextGenerate
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "50", "(context) == (kKeyContextGenerate)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
51 CHECK(args[*offset + 1]->IsUndefined())do { if (__builtin_expect(!!(!(args[*offset + 1]->IsUndefined
())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "51", "args[*offset + 1]->IsUndefined()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
52 config->output_key_object_ = true;
53 } else {
54 config->output_key_object_ = false;
55
56 CHECK(args[*offset]->IsInt32())do { if (__builtin_expect(!!(!(args[*offset]->IsInt32())),
0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "56", "args[*offset]->IsInt32()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
57 config->format_ = static_cast<PKFormatType>(
58 args[*offset].As<Int32>()->Value());
59
60 if (args[*offset + 1]->IsInt32()) {
61 config->type_ = Just<PKEncodingType>(static_cast<PKEncodingType>(
62 args[*offset + 1].As<Int32>()->Value()));
63 } else {
64 CHECK(do { if (__builtin_expect(!!(!((context == kKeyContextInput &&
config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate
&& config->format_ == kKeyFormatJWK))), 0)) { do {
static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "68", "(context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
65 (context == kKeyContextInput &&do { if (__builtin_expect(!!(!((context == kKeyContextInput &&
config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate
&& config->format_ == kKeyFormatJWK))), 0)) { do {
static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "68", "(context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
66 config->format_ == kKeyFormatPEM) ||do { if (__builtin_expect(!!(!((context == kKeyContextInput &&
config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate
&& config->format_ == kKeyFormatJWK))), 0)) { do {
static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "68", "(context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
67 (context == kKeyContextGenerate &&do { if (__builtin_expect(!!(!((context == kKeyContextInput &&
config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate
&& config->format_ == kKeyFormatJWK))), 0)) { do {
static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "68", "(context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
68 config->format_ == kKeyFormatJWK))do { if (__builtin_expect(!!(!((context == kKeyContextInput &&
config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate
&& config->format_ == kKeyFormatJWK))), 0)) { do {
static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "68", "(context == kKeyContextInput && config->format_ == kKeyFormatPEM) || (context == kKeyContextGenerate && config->format_ == kKeyFormatJWK)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
69 CHECK(args[*offset + 1]->IsNullOrUndefined())do { if (__builtin_expect(!!(!(args[*offset + 1]->IsNullOrUndefined
())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "69", "args[*offset + 1]->IsNullOrUndefined()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
70 config->type_ = Nothing<PKEncodingType>();
71 }
72 }
73
74 *offset += 2;
75}
76
77ParseKeyResult TryParsePublicKey(
78 EVPKeyPointer* pkey,
79 const BIOPointer& bp,
80 const char* name,
81 // NOLINTNEXTLINE(runtime/int)
82 const std::function<EVP_PKEY*(const unsigned char** p, long l)>& parse) {
83 unsigned char* der_data;
84 long der_len; // NOLINT(runtime/int)
85
86 // This skips surrounding data and decodes PEM to DER.
87 {
88 MarkPopErrorOnReturn mark_pop_error_on_return;
89 if (PEM_bytes_read_bio(&der_data, &der_len, nullptr, name,
90 bp.get(), nullptr, nullptr) != 1)
91 return ParseKeyResult::kParseKeyNotRecognized;
92 }
93
94 // OpenSSL might modify the pointer, so we need to make a copy before parsing.
95 const unsigned char* p = der_data;
96 pkey->reset(parse(&p, der_len));
97 OPENSSL_clear_free(der_data, der_len)CRYPTO_clear_free(der_data, der_len, "../src/crypto/crypto_keys.cc"
, 97)
;
98
99 return *pkey ? ParseKeyResult::kParseKeyOk :
100 ParseKeyResult::kParseKeyFailed;
101}
102
103ParseKeyResult ParsePublicKeyPEM(EVPKeyPointer* pkey,
104 const char* key_pem,
105 int key_pem_len) {
106 BIOPointer bp(BIO_new_mem_buf(const_cast<char*>(key_pem), key_pem_len));
107 if (!bp)
108 return ParseKeyResult::kParseKeyFailed;
109
110 ParseKeyResult ret;
111
112 // Try parsing as a SubjectPublicKeyInfo first.
113 ret = TryParsePublicKey(pkey, bp, "PUBLIC KEY",
114 [](const unsigned char** p, long l) { // NOLINT(runtime/int)
115 return d2i_PUBKEY(nullptr, p, l);
116 });
117 if (ret != ParseKeyResult::kParseKeyNotRecognized)
118 return ret;
119
120 // Maybe it is PKCS#1.
121 CHECK(BIO_reset(bp.get()))do { if (__builtin_expect(!!(!((int)BIO_ctrl(bp.get(),1,0,__null
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "121", "(int)BIO_ctrl(bp.get(),1,0,__null)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
122 ret = TryParsePublicKey(pkey, bp, "RSA PUBLIC KEY",
123 [](const unsigned char** p, long l) { // NOLINT(runtime/int)
124 return d2i_PublicKey(EVP_PKEY_RSA6, nullptr, p, l);
125 });
126 if (ret != ParseKeyResult::kParseKeyNotRecognized)
127 return ret;
128
129 // X.509 fallback.
130 CHECK(BIO_reset(bp.get()))do { if (__builtin_expect(!!(!((int)BIO_ctrl(bp.get(),1,0,__null
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "130", "(int)BIO_ctrl(bp.get(),1,0,__null)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
131 return TryParsePublicKey(pkey, bp, "CERTIFICATE",
132 [](const unsigned char** p, long l) { // NOLINT(runtime/int)
133 X509Pointer x509(d2i_X509(nullptr, p, l));
134 return x509 ? X509_get_pubkey(x509.get()) : nullptr;
135 });
136}
137
138ParseKeyResult ParsePublicKey(EVPKeyPointer* pkey,
139 const PublicKeyEncodingConfig& config,
140 const char* key,
141 size_t key_len) {
142 if (config.format_ == kKeyFormatPEM) {
143 return ParsePublicKeyPEM(pkey, key, key_len);
144 } else {
145 CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "145", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
146
147 const unsigned char* p = reinterpret_cast<const unsigned char*>(key);
148 if (config.type_.ToChecked() == kKeyEncodingPKCS1) {
149 pkey->reset(d2i_PublicKey(EVP_PKEY_RSA6, nullptr, &p, key_len));
150 } else {
151 CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSPKI)do { if (__builtin_expect(!!(!((config.type_.ToChecked()) == (
kKeyEncodingSPKI))), 0)) { do { static const node::AssertionInfo
args = { "../src/crypto/crypto_keys.cc" ":" "151", "(config.type_.ToChecked()) == (kKeyEncodingSPKI)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
152 pkey->reset(d2i_PUBKEY(nullptr, &p, key_len));
153 }
154
155 return *pkey ? ParseKeyResult::kParseKeyOk :
156 ParseKeyResult::kParseKeyFailed;
157 }
158}
159
160bool IsASN1Sequence(const unsigned char* data, size_t size,
161 size_t* data_offset, size_t* data_size) {
162 if (size < 2 || data[0] != 0x30)
163 return false;
164
165 if (data[1] & 0x80) {
166 // Long form.
167 size_t n_bytes = data[1] & ~0x80;
168 if (n_bytes + 2 > size || n_bytes > sizeof(size_t))
169 return false;
170 size_t length = 0;
171 for (size_t i = 0; i < n_bytes; i++)
172 length = (length << 8) | data[i + 2];
173 *data_offset = 2 + n_bytes;
174 *data_size = std::min(size - 2 - n_bytes, length);
175 } else {
176 // Short form.
177 *data_offset = 2;
178 *data_size = std::min<size_t>(size - 2, data[1]);
179 }
180
181 return true;
182}
183
184bool IsRSAPrivateKey(const unsigned char* data, size_t size) {
185 // Both RSAPrivateKey and RSAPublicKey structures start with a SEQUENCE.
186 size_t offset, len;
187 if (!IsASN1Sequence(data, size, &offset, &len))
188 return false;
189
190 // An RSAPrivateKey sequence always starts with a single-byte integer whose
191 // value is either 0 or 1, whereas an RSAPublicKey starts with the modulus
192 // (which is the product of two primes and therefore at least 4), so we can
193 // decide the type of the structure based on the first three bytes of the
194 // sequence.
195 return len >= 3 &&
196 data[offset] == 2 &&
197 data[offset + 1] == 1 &&
198 !(data[offset + 2] & 0xfe);
199}
200
201bool IsEncryptedPrivateKeyInfo(const unsigned char* data, size_t size) {
202 // Both PrivateKeyInfo and EncryptedPrivateKeyInfo start with a SEQUENCE.
203 size_t offset, len;
204 if (!IsASN1Sequence(data, size, &offset, &len))
205 return false;
206
207 // A PrivateKeyInfo sequence always starts with an integer whereas an
208 // EncryptedPrivateKeyInfo starts with an AlgorithmIdentifier.
209 return len >= 1 &&
210 data[offset] != 2;
211}
212
213ParseKeyResult ParsePrivateKey(EVPKeyPointer* pkey,
214 const PrivateKeyEncodingConfig& config,
215 const char* key,
216 size_t key_len) {
217 const ByteSource* passphrase = config.passphrase_.get();
218
219 if (config.format_ == kKeyFormatPEM) {
220 BIOPointer bio(BIO_new_mem_buf(key, key_len));
221 if (!bio)
222 return ParseKeyResult::kParseKeyFailed;
223
224 pkey->reset(PEM_read_bio_PrivateKey(bio.get(),
225 nullptr,
226 PasswordCallback,
227 &passphrase));
228 } else {
229 CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "229", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
230
231 if (config.type_.ToChecked() == kKeyEncodingPKCS1) {
232 const unsigned char* p = reinterpret_cast<const unsigned char*>(key);
233 pkey->reset(d2i_PrivateKey(EVP_PKEY_RSA6, nullptr, &p, key_len));
234 } else if (config.type_.ToChecked() == kKeyEncodingPKCS8) {
235 BIOPointer bio(BIO_new_mem_buf(key, key_len));
236 if (!bio)
237 return ParseKeyResult::kParseKeyFailed;
238
239 if (IsEncryptedPrivateKeyInfo(
240 reinterpret_cast<const unsigned char*>(key), key_len)) {
241 pkey->reset(d2i_PKCS8PrivateKey_bio(bio.get(),
242 nullptr,
243 PasswordCallback,
244 &passphrase));
245 } else {
246 PKCS8Pointer p8inf(d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), nullptr));
247 if (p8inf)
248 pkey->reset(EVP_PKCS82PKEY(p8inf.get()));
249 }
250 } else {
251 CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSEC1)do { if (__builtin_expect(!!(!((config.type_.ToChecked()) == (
kKeyEncodingSEC1))), 0)) { do { static const node::AssertionInfo
args = { "../src/crypto/crypto_keys.cc" ":" "251", "(config.type_.ToChecked()) == (kKeyEncodingSEC1)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
252 const unsigned char* p = reinterpret_cast<const unsigned char*>(key);
253 pkey->reset(d2i_PrivateKey(EVP_PKEY_EC408, nullptr, &p, key_len));
254 }
255 }
256
257 // OpenSSL can fail to parse the key but still return a non-null pointer.
258 unsigned long err = ERR_peek_error(); // NOLINT(runtime/int)
259 if (err != 0)
260 pkey->reset();
261
262 if (*pkey)
263 return ParseKeyResult::kParseKeyOk;
264 if (ERR_GET_LIB(err) == ERR_LIB_PEM9 &&
265 ERR_GET_REASON(err) == PEM_R_BAD_PASSWORD_READ104) {
266 if (config.passphrase_.IsEmpty())
267 return ParseKeyResult::kParseKeyNeedPassphrase;
268 }
269 return ParseKeyResult::kParseKeyFailed;
270}
271
272MaybeLocal<Value> BIOToStringOrBuffer(
273 Environment* env,
274 BIO* bio,
275 PKFormatType format) {
276 BUF_MEM* bptr;
277 BIO_get_mem_ptr(bio, &bptr)BIO_ctrl(bio,115,0, (char *)(&bptr));
278 if (format == kKeyFormatPEM) {
279 // PEM is an ASCII format, so we will return it as a string.
280 return String::NewFromUtf8(env->isolate(), bptr->data,
281 NewStringType::kNormal,
282 bptr->length).FromMaybe(Local<Value>());
283 } else {
284 CHECK_EQ(format, kKeyFormatDER)do { if (__builtin_expect(!!(!((format) == (kKeyFormatDER))),
0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "284", "(format) == (kKeyFormatDER)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
285 // DER is binary, return it as a buffer.
286 return Buffer::Copy(env, bptr->data, bptr->length)
287 .FromMaybe(Local<Value>());
288 }
289}
290
291
292MaybeLocal<Value> WritePrivateKey(
293 Environment* env,
294 EVP_PKEY* pkey,
295 const PrivateKeyEncodingConfig& config) {
296 BIOPointer bio(BIO_new(BIO_s_mem()));
297 CHECK(bio)do { if (__builtin_expect(!!(!(bio)), 0)) { do { static const
node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":"
"297", "bio", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
;
298
299 // If an empty string was passed as the passphrase, the ByteSource might
300 // contain a null pointer, which OpenSSL will ignore, causing it to invoke its
301 // default passphrase callback, which would block the thread until the user
302 // manually enters a passphrase. We could supply our own passphrase callback
303 // to handle this special case, but it is easier to avoid passing a null
304 // pointer to OpenSSL.
305 char* pass = nullptr;
306 size_t pass_len = 0;
307 if (!config.passphrase_.IsEmpty()) {
308 pass = const_cast<char*>(config.passphrase_->data<char>());
309 pass_len = config.passphrase_->size();
310 if (pass == nullptr) {
311 // OpenSSL will not actually dereference this pointer, so it can be any
312 // non-null pointer. We cannot assert that directly, which is why we
313 // intentionally use a pointer that will likely cause a segmentation fault
314 // when dereferenced.
315 CHECK_EQ(pass_len, 0)do { if (__builtin_expect(!!(!((pass_len) == (0))), 0)) { do {
static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "315", "(pass_len) == (0)", __PRETTY_FUNCTION__ }; node::
Assert(args); } while (0); } } while (0)
;
316 pass = reinterpret_cast<char*>(-1);
317 CHECK_NE(pass, nullptr)do { if (__builtin_expect(!!(!((pass) != (nullptr))), 0)) { do
{ static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "317", "(pass) != (nullptr)", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
318 }
319 }
320
321 bool err;
322
323 PKEncodingType encoding_type = config.type_.ToChecked();
324 if (encoding_type == kKeyEncodingPKCS1) {
325 // PKCS#1 is only permitted for RSA keys.
326 CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_RSA)do { if (__builtin_expect(!!(!((EVP_PKEY_get_id(pkey)) == (6)
)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "326", "(EVP_PKEY_get_id(pkey)) == (6)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
327
328 RSAPointer rsa(EVP_PKEY_get1_RSA(pkey));
329 if (config.format_ == kKeyFormatPEM) {
330 // Encode PKCS#1 as PEM.
331 err = PEM_write_bio_RSAPrivateKey(
332 bio.get(), rsa.get(),
333 config.cipher_,
334 reinterpret_cast<unsigned char*>(pass),
335 pass_len,
336 nullptr, nullptr) != 1;
337 } else {
338 // Encode PKCS#1 as DER. This does not permit encryption.
339 CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "339", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
340 CHECK_NULL(config.cipher_)do { if (__builtin_expect(!!(!((config.cipher_) == nullptr)),
0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "340", "(config.cipher_) == nullptr", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
341 err = i2d_RSAPrivateKey_bio(bio.get(), rsa.get()) != 1;
342 }
343 } else if (encoding_type == kKeyEncodingPKCS8) {
344 if (config.format_ == kKeyFormatPEM) {
345 // Encode PKCS#8 as PEM.
346 err = PEM_write_bio_PKCS8PrivateKey(
347 bio.get(), pkey,
348 config.cipher_,
349 pass,
350 pass_len,
351 nullptr, nullptr) != 1;
352 } else {
353 // Encode PKCS#8 as DER.
354 CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "354", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
355 err = i2d_PKCS8PrivateKey_bio(
356 bio.get(), pkey,
357 config.cipher_,
358 pass,
359 pass_len,
360 nullptr, nullptr) != 1;
361 }
362 } else {
363 CHECK_EQ(encoding_type, kKeyEncodingSEC1)do { if (__builtin_expect(!!(!((encoding_type) == (kKeyEncodingSEC1
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "363", "(encoding_type) == (kKeyEncodingSEC1)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
364
365 // SEC1 is only permitted for EC keys.
366 CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_EC)do { if (__builtin_expect(!!(!((EVP_PKEY_get_id(pkey)) == (408
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "366", "(EVP_PKEY_get_id(pkey)) == (408)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
367
368 ECKeyPointer ec_key(EVP_PKEY_get1_EC_KEY(pkey));
369 if (config.format_ == kKeyFormatPEM) {
370 // Encode SEC1 as PEM.
371 err = PEM_write_bio_ECPrivateKey(
372 bio.get(), ec_key.get(),
373 config.cipher_,
374 reinterpret_cast<unsigned char*>(pass),
375 pass_len,
376 nullptr, nullptr) != 1;
377 } else {
378 // Encode SEC1 as DER. This does not permit encryption.
379 CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "379", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
380 CHECK_NULL(config.cipher_)do { if (__builtin_expect(!!(!((config.cipher_) == nullptr)),
0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "380", "(config.cipher_) == nullptr", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
381 err = i2d_ECPrivateKey_bio(bio.get(), ec_key.get()) != 1;
382 }
383 }
384
385 if (err) {
386 ThrowCryptoError(env, ERR_get_error(), "Failed to encode private key");
387 return MaybeLocal<Value>();
388 }
389 return BIOToStringOrBuffer(env, bio.get(), config.format_);
390}
391
392bool WritePublicKeyInner(EVP_PKEY* pkey,
393 const BIOPointer& bio,
394 const PublicKeyEncodingConfig& config) {
395 if (config.type_.ToChecked() == kKeyEncodingPKCS1) {
396 // PKCS#1 is only valid for RSA keys.
397 CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_RSA)do { if (__builtin_expect(!!(!((EVP_PKEY_get_id(pkey)) == (6)
)), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "397", "(EVP_PKEY_get_id(pkey)) == (6)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
398 RSAPointer rsa(EVP_PKEY_get1_RSA(pkey));
399 if (config.format_ == kKeyFormatPEM) {
400 // Encode PKCS#1 as PEM.
401 return PEM_write_bio_RSAPublicKey(bio.get(), rsa.get()) == 1;
402 } else {
403 // Encode PKCS#1 as DER.
404 CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "404", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
405 return i2d_RSAPublicKey_bio(bio.get(), rsa.get()) == 1;
406 }
407 } else {
408 CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSPKI)do { if (__builtin_expect(!!(!((config.type_.ToChecked()) == (
kKeyEncodingSPKI))), 0)) { do { static const node::AssertionInfo
args = { "../src/crypto/crypto_keys.cc" ":" "408", "(config.type_.ToChecked()) == (kKeyEncodingSPKI)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
409 if (config.format_ == kKeyFormatPEM) {
410 // Encode SPKI as PEM.
411 return PEM_write_bio_PUBKEY(bio.get(), pkey) == 1;
412 } else {
413 // Encode SPKI as DER.
414 CHECK_EQ(config.format_, kKeyFormatDER)do { if (__builtin_expect(!!(!((config.format_) == (kKeyFormatDER
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "414", "(config.format_) == (kKeyFormatDER)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
415 return i2d_PUBKEY_bio(bio.get(), pkey) == 1;
416 }
417 }
418}
419
420MaybeLocal<Value> WritePublicKey(Environment* env,
421 EVP_PKEY* pkey,
422 const PublicKeyEncodingConfig& config) {
423 BIOPointer bio(BIO_new(BIO_s_mem()));
424 CHECK(bio)do { if (__builtin_expect(!!(!(bio)), 0)) { do { static const
node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":"
"424", "bio", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
;
425
426 if (!WritePublicKeyInner(pkey, bio, config)) {
427 ThrowCryptoError(env, ERR_get_error(), "Failed to encode public key");
428 return MaybeLocal<Value>();
429 }
430 return BIOToStringOrBuffer(env, bio.get(), config.format_);
431}
432
433Maybe<bool> ExportJWKSecretKey(
434 Environment* env,
435 std::shared_ptr<KeyObjectData> key,
436 Local<Object> target) {
437 CHECK_EQ(key->GetKeyType(), kKeyTypeSecret)do { if (__builtin_expect(!!(!((key->GetKeyType()) == (kKeyTypeSecret
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "437", "(key->GetKeyType()) == (kKeyTypeSecret)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
438
439 Local<Value> error;
440 Local<Value> raw;
441 MaybeLocal<Value> key_data =
442 StringBytes::Encode(
443 env->isolate(),
444 key->GetSymmetricKey(),
445 key->GetSymmetricKeySize(),
446 BASE64URL,
447 &error);
448 if (key_data.IsEmpty()) {
449 CHECK(!error.IsEmpty())do { if (__builtin_expect(!!(!(!error.IsEmpty())), 0)) { do {
static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "449", "!error.IsEmpty()", __PRETTY_FUNCTION__ }; node::
Assert(args); } while (0); } } while (0)
;
450 env->isolate()->ThrowException(error);
451 return Nothing<bool>();
452 }
453 if (!key_data.ToLocal(&raw))
454 return Nothing<bool>();
455
456 if (target->Set(
457 env->context(),
458 env->jwk_kty_string(),
459 env->jwk_oct_string()).IsNothing() ||
460 target->Set(
461 env->context(),
462 env->jwk_k_string(),
463 raw).IsNothing()) {
464 return Nothing<bool>();
465 }
466
467 return Just(true);
468}
469
470std::shared_ptr<KeyObjectData> ImportJWKSecretKey(
471 Environment* env,
472 Local<Object> jwk) {
473 Local<Value> key;
474 if (!jwk->Get(env->context(), env->jwk_k_string()).ToLocal(&key) ||
475 !key->IsString()) {
476 THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK secret key format");
477 return std::shared_ptr<KeyObjectData>();
478 }
479
480 ByteSource key_data = ByteSource::FromEncodedString(env, key.As<String>());
481 if (key_data.size() > INT_MAX2147483647) {
482 THROW_ERR_CRYPTO_INVALID_KEYLEN(env);
483 return std::shared_ptr<KeyObjectData>();
484 }
485
486 return KeyObjectData::CreateSecret(std::move(key_data));
487}
488
489Maybe<bool> ExportJWKAsymmetricKey(
490 Environment* env,
491 std::shared_ptr<KeyObjectData> key,
492 Local<Object> target,
493 bool handleRsaPss) {
494 switch (EVP_PKEY_idEVP_PKEY_get_id(key->GetAsymmetricKey().get())) {
495 case EVP_PKEY_RSA_PSS912: {
496 if (handleRsaPss) return ExportJWKRsaKey(env, key, target);
497 break;
498 }
499 case EVP_PKEY_RSA6: return ExportJWKRsaKey(env, key, target);
500 case EVP_PKEY_EC408: return ExportJWKEcKey(env, key, target).IsJust() ?
501 Just(true) : Nothing<bool>();
502 case EVP_PKEY_ED255191087:
503 // Fall through
504 case EVP_PKEY_ED4481088:
505 // Fall through
506 case EVP_PKEY_X255191034:
507 // Fall through
508 case EVP_PKEY_X4481035: return ExportJWKEdKey(env, key, target);
509 }
510 THROW_ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE(env);
511 return Just(false);
512}
513
514std::shared_ptr<KeyObjectData> ImportJWKAsymmetricKey(
515 Environment* env,
516 Local<Object> jwk,
517 const char* kty,
518 const FunctionCallbackInfo<Value>& args,
519 unsigned int offset) {
520 if (strcmp(kty, "RSA") == 0) {
521 return ImportJWKRsaKey(env, jwk, args, offset);
522 } else if (strcmp(kty, "EC") == 0) {
523 return ImportJWKEcKey(env, jwk, args, offset);
524 }
525
526 THROW_ERR_CRYPTO_INVALID_JWK(env, "%s is not a supported JWK key type", kty);
527 return std::shared_ptr<KeyObjectData>();
528}
529
530Maybe<bool> GetSecretKeyDetail(
531 Environment* env,
532 std::shared_ptr<KeyObjectData> key,
533 Local<Object> target) {
534 // For the secret key detail, all we care about is the length,
535 // converted to bits.
536
537 size_t length = key->GetSymmetricKeySize() * CHAR_BIT8;
538 return target->Set(env->context(),
539 env->length_string(),
540 Number::New(env->isolate(), static_cast<double>(length)));
541}
542
543Maybe<bool> GetAsymmetricKeyDetail(
544 Environment* env,
545 std::shared_ptr<KeyObjectData> key,
546 Local<Object> target) {
547 switch (EVP_PKEY_idEVP_PKEY_get_id(key->GetAsymmetricKey().get())) {
548 case EVP_PKEY_RSA6:
549 // Fall through
550 case EVP_PKEY_RSA_PSS912: return GetRsaKeyDetail(env, key, target);
551 case EVP_PKEY_DSA116: return GetDsaKeyDetail(env, key, target);
552 case EVP_PKEY_EC408: return GetEcKeyDetail(env, key, target);
553 case EVP_PKEY_DH28: return GetDhKeyDetail(env, key, target);
554 }
555 THROW_ERR_CRYPTO_INVALID_KEYTYPE(env);
556 return Nothing<bool>();
557}
558} // namespace
559
560ManagedEVPPKey::ManagedEVPPKey(EVPKeyPointer&& pkey) : pkey_(std::move(pkey)),
561 mutex_(std::make_shared<Mutex>()) {}
562
563ManagedEVPPKey::ManagedEVPPKey(const ManagedEVPPKey& that) {
564 *this = that;
565}
566
567ManagedEVPPKey& ManagedEVPPKey::operator=(const ManagedEVPPKey& that) {
568 Mutex::ScopedLock lock(*that.mutex_);
569
570 pkey_.reset(that.get());
571
572 if (pkey_)
573 EVP_PKEY_up_ref(pkey_.get());
574
575 mutex_ = that.mutex_;
576
577 return *this;
578}
579
580ManagedEVPPKey::operator bool() const {
581 return !!pkey_;
582}
583
584EVP_PKEY* ManagedEVPPKey::get() const {
585 return pkey_.get();
586}
587
588Mutex* ManagedEVPPKey::mutex() const {
589 return mutex_.get();
590}
591
592void ManagedEVPPKey::MemoryInfo(MemoryTracker* tracker) const {
593 tracker->TrackFieldWithSize("pkey",
594 !pkey_ ? 0 : kSizeOf_EVP_PKEY +
595 size_of_private_key() +
596 size_of_public_key());
597}
598
599size_t ManagedEVPPKey::size_of_private_key() const {
600 size_t len = 0;
601 return (pkey_ && EVP_PKEY_get_raw_private_key(
602 pkey_.get(), nullptr, &len) == 1) ? len : 0;
603}
604
605size_t ManagedEVPPKey::size_of_public_key() const {
606 size_t len = 0;
607 return (pkey_ && EVP_PKEY_get_raw_public_key(
608 pkey_.get(), nullptr, &len) == 1) ? len : 0;
609}
610
611// This maps true to Just<bool>(true) and false to Nothing<bool>().
612static inline Maybe<bool> Tristate(bool b) {
613 return b ? Just(true) : Nothing<bool>();
614}
615
616Maybe<bool> ExportJWKInner(Environment* env,
617 std::shared_ptr<KeyObjectData> key,
618 Local<Value> result,
619 bool handleRsaPss) {
620 switch (key->GetKeyType()) {
621 case kKeyTypeSecret:
622 return ExportJWKSecretKey(env, key, result.As<Object>());
623 case kKeyTypePublic:
624 // Fall through
625 case kKeyTypePrivate:
626 return ExportJWKAsymmetricKey(
627 env, key, result.As<Object>(), handleRsaPss);
628 default:
629 UNREACHABLE()do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "629", "\"Unreachable code reached\"", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0)
;
630 }
631}
632
633Maybe<bool> ManagedEVPPKey::ToEncodedPublicKey(
634 Environment* env,
635 ManagedEVPPKey key,
636 const PublicKeyEncodingConfig& config,
637 Local<Value>* out) {
638 if (!key) return Nothing<bool>();
639 if (config.output_key_object_) {
640 // Note that this has the downside of containing sensitive data of the
641 // private key.
642 std::shared_ptr<KeyObjectData> data =
643 KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key));
644 return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out));
645 } else if (config.format_ == kKeyFormatJWK) {
646 std::shared_ptr<KeyObjectData> data =
647 KeyObjectData::CreateAsymmetric(kKeyTypePublic, std::move(key));
648 *out = Object::New(env->isolate());
649 return ExportJWKInner(env, data, *out, false);
650 }
651
652 return Tristate(WritePublicKey(env, key.get(), config).ToLocal(out));
653}
654
655Maybe<bool> ManagedEVPPKey::ToEncodedPrivateKey(
656 Environment* env,
657 ManagedEVPPKey key,
658 const PrivateKeyEncodingConfig& config,
659 Local<Value>* out) {
660 if (!key) return Nothing<bool>();
661 if (config.output_key_object_) {
662 std::shared_ptr<KeyObjectData> data =
663 KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key));
664 return Tristate(KeyObjectHandle::Create(env, data).ToLocal(out));
665 } else if (config.format_ == kKeyFormatJWK) {
666 std::shared_ptr<KeyObjectData> data =
667 KeyObjectData::CreateAsymmetric(kKeyTypePrivate, std::move(key));
668 *out = Object::New(env->isolate());
669 return ExportJWKInner(env, data, *out, false);
670 }
671
672 return Tristate(WritePrivateKey(env, key.get(), config).ToLocal(out));
673}
674
675NonCopyableMaybe<PrivateKeyEncodingConfig>
676ManagedEVPPKey::GetPrivateKeyEncodingFromJs(
677 const FunctionCallbackInfo<Value>& args,
678 unsigned int* offset,
679 KeyEncodingContext context) {
680 Environment* env = Environment::GetCurrent(args);
681
682 PrivateKeyEncodingConfig result;
683 GetKeyFormatAndTypeFromJs(&result, args, offset, context);
684
685 if (result.output_key_object_
13.1
Field 'output_key_object_' is false
13.1
Field 'output_key_object_' is false
13.1
Field 'output_key_object_' is false
) {
14
Taking false branch
686 if (context != kKeyContextInput)
687 (*offset)++;
688 } else {
689 bool needs_passphrase = false;
690 if (context
14.1
'context' is equal to kKeyContextInput
14.1
'context' is equal to kKeyContextInput
14.1
'context' is equal to kKeyContextInput
!= kKeyContextInput) {
15
Taking false branch
691 if (args[*offset]->IsString()) {
692 Utf8Value cipher_name(env->isolate(), args[*offset]);
693 result.cipher_ = EVP_get_cipherbyname(*cipher_name);
694 if (result.cipher_ == nullptr) {
695 THROW_ERR_CRYPTO_UNKNOWN_CIPHER(env);
696 return NonCopyableMaybe<PrivateKeyEncodingConfig>();
697 }
698 needs_passphrase = true;
699 } else {
700 CHECK(args[*offset]->IsNullOrUndefined())do { if (__builtin_expect(!!(!(args[*offset]->IsNullOrUndefined
())), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "700", "args[*offset]->IsNullOrUndefined()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
701 result.cipher_ = nullptr;
702 }
703 (*offset)++;
704 }
705
706 if (IsAnyByteSource(args[*offset])) {
16
Assuming the condition is false
17
Taking false branch
707 CHECK_IMPLIES(context != kKeyContextInput, result.cipher_ != nullptr)do { if (__builtin_expect(!!(!(!(context != kKeyContextInput)
|| (result.cipher_ != nullptr))), 0)) { do { static const node
::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "707"
, "!(context != kKeyContextInput) || (result.cipher_ != nullptr)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
708 ArrayBufferOrViewContents<char> passphrase(args[*offset]);
709 if (UNLIKELY(!passphrase.CheckSizeInt32())__builtin_expect(!!(!passphrase.CheckSizeInt32()), 0)) {
710 THROW_ERR_OUT_OF_RANGE(env, "passphrase is too big");
711 return NonCopyableMaybe<PrivateKeyEncodingConfig>();
712 }
713 result.passphrase_ = NonCopyableMaybe<ByteSource>(
714 passphrase.ToNullTerminatedCopy());
715 } else {
716 CHECK(args[*offset]->IsNullOrUndefined() && !needs_passphrase)do { if (__builtin_expect(!!(!(args[*offset]->IsNullOrUndefined
() && !needs_passphrase)), 0)) { do { static const node
::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":" "716"
, "args[*offset]->IsNullOrUndefined() && !needs_passphrase"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
18
Taking false branch
19
Loop condition is false. Exiting loop
717 }
718 }
719
720 (*offset)++;
721 return NonCopyableMaybe<PrivateKeyEncodingConfig>(std::move(result));
20
Calling constructor for 'NonCopyableMaybe<node::crypto::PrivateKeyEncodingConfig>'
722}
723
724PublicKeyEncodingConfig ManagedEVPPKey::GetPublicKeyEncodingFromJs(
725 const FunctionCallbackInfo<Value>& args,
726 unsigned int* offset,
727 KeyEncodingContext context) {
728 PublicKeyEncodingConfig result;
729 GetKeyFormatAndTypeFromJs(&result, args, offset, context);
730 return result;
731}
732
733ManagedEVPPKey ManagedEVPPKey::GetPrivateKeyFromJs(
734 const FunctionCallbackInfo<Value>& args,
735 unsigned int* offset,
736 bool allow_key_object) {
737 if (args[*offset]->IsString() || IsAnyByteSource(args[*offset])) {
12
Taking true branch
738 Environment* env = Environment::GetCurrent(args);
739 ByteSource key = ByteSource::FromStringOrBuffer(env, args[(*offset)++]);
740 NonCopyableMaybe<PrivateKeyEncodingConfig> config =
741 GetPrivateKeyEncodingFromJs(args, offset, kKeyContextInput);
13
Calling 'ManagedEVPPKey::GetPrivateKeyEncodingFromJs'
742 if (config.IsEmpty())
743 return ManagedEVPPKey();
744
745 EVPKeyPointer pkey;
746 ParseKeyResult ret =
747 ParsePrivateKey(&pkey, config.Release(), key.data<char>(), key.size());
748 return GetParsedKey(env, std::move(pkey), ret,
749 "Failed to read private key");
750 } else {
751 CHECK(args[*offset]->IsObject() && allow_key_object)do { if (__builtin_expect(!!(!(args[*offset]->IsObject() &&
allow_key_object)), 0)) { do { static const node::AssertionInfo
args = { "../src/crypto/crypto_keys.cc" ":" "751", "args[*offset]->IsObject() && allow_key_object"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
752 KeyObjectHandle* key;
753 ASSIGN_OR_RETURN_UNWRAP(&key, args[*offset].As<Object>(), ManagedEVPPKey())do { *&key = static_cast<typename std::remove_reference
<decltype(*&key)>::type>( BaseObject::FromJSObject
(args[*offset].As<Object>())); if (*&key == nullptr
) return ManagedEVPPKey(); } while (0)
;
754 CHECK_EQ(key->Data()->GetKeyType(), kKeyTypePrivate)do { if (__builtin_expect(!!(!((key->Data()->GetKeyType
()) == (kKeyTypePrivate))), 0)) { do { static const node::AssertionInfo
args = { "../src/crypto/crypto_keys.cc" ":" "754", "(key->Data()->GetKeyType()) == (kKeyTypePrivate)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
755 (*offset) += 4;
756 return key->Data()->GetAsymmetricKey();
757 }
758}
759
760ManagedEVPPKey ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(
761 const FunctionCallbackInfo<Value>& args,
762 unsigned int* offset) {
763 if (IsAnyByteSource(args[*offset])) {
764 Environment* env = Environment::GetCurrent(args);
765 ArrayBufferOrViewContents<char> data(args[(*offset)++]);
766 if (UNLIKELY(!data.CheckSizeInt32())__builtin_expect(!!(!data.CheckSizeInt32()), 0)) {
767 THROW_ERR_OUT_OF_RANGE(env, "keyData is too big");
768 return ManagedEVPPKey();
769 }
770 NonCopyableMaybe<PrivateKeyEncodingConfig> config_ =
771 GetPrivateKeyEncodingFromJs(args, offset, kKeyContextInput);
772 if (config_.IsEmpty())
773 return ManagedEVPPKey();
774
775 ParseKeyResult ret;
776 PrivateKeyEncodingConfig config = config_.Release();
777 EVPKeyPointer pkey;
778 if (config.format_ == kKeyFormatPEM) {
779 // For PEM, we can easily determine whether it is a public or private key
780 // by looking for the respective PEM tags.
781 ret = ParsePublicKeyPEM(&pkey, data.data(), data.size());
782 if (ret == ParseKeyResult::kParseKeyNotRecognized) {
783 ret = ParsePrivateKey(&pkey, config, data.data(), data.size());
784 }
785 } else {
786 // For DER, the type determines how to parse it. SPKI, PKCS#8 and SEC1 are
787 // easy, but PKCS#1 can be a public key or a private key.
788 bool is_public;
789 switch (config.type_.ToChecked()) {
790 case kKeyEncodingPKCS1:
791 is_public = !IsRSAPrivateKey(
792 reinterpret_cast<const unsigned char*>(data.data()), data.size());
793 break;
794 case kKeyEncodingSPKI:
795 is_public = true;
796 break;
797 case kKeyEncodingPKCS8:
798 case kKeyEncodingSEC1:
799 is_public = false;
800 break;
801 default:
802 UNREACHABLE("Invalid key encoding type")do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "802", "\"Unreachable code reached\" \": \" \"Invalid key encoding type\""
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0)
;
803 }
804
805 if (is_public) {
806 ret = ParsePublicKey(&pkey, config, data.data(), data.size());
807 } else {
808 ret = ParsePrivateKey(&pkey, config, data.data(), data.size());
809 }
810 }
811
812 return ManagedEVPPKey::GetParsedKey(
813 env, std::move(pkey), ret, "Failed to read asymmetric key");
814 } else {
815 CHECK(args[*offset]->IsObject())do { if (__builtin_expect(!!(!(args[*offset]->IsObject()))
, 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "815", "args[*offset]->IsObject()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
816 KeyObjectHandle* key = Unwrap<KeyObjectHandle>(args[*offset].As<Object>());
817 CHECK_NOT_NULL(key)do { if (__builtin_expect(!!(!((key) != nullptr)), 0)) { do {
static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "817", "(key) != nullptr", __PRETTY_FUNCTION__ }; node::
Assert(args); } while (0); } } while (0)
;
818 CHECK_NE(key->Data()->GetKeyType(), kKeyTypeSecret)do { if (__builtin_expect(!!(!((key->Data()->GetKeyType
()) != (kKeyTypeSecret))), 0)) { do { static const node::AssertionInfo
args = { "../src/crypto/crypto_keys.cc" ":" "818", "(key->Data()->GetKeyType()) != (kKeyTypeSecret)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
819 (*offset) += 4;
820 return key->Data()->GetAsymmetricKey();
821 }
822}
823
824ManagedEVPPKey ManagedEVPPKey::GetParsedKey(Environment* env,
825 EVPKeyPointer&& pkey,
826 ParseKeyResult ret,
827 const char* default_msg) {
828 switch (ret) {
829 case ParseKeyResult::kParseKeyOk:
830 CHECK(pkey)do { if (__builtin_expect(!!(!(pkey)), 0)) { do { static const
node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":"
"830", "pkey", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
;
831 break;
832 case ParseKeyResult::kParseKeyNeedPassphrase:
833 THROW_ERR_MISSING_PASSPHRASE(env,
834 "Passphrase required for encrypted key");
835 break;
836 default:
837 ThrowCryptoError(env, ERR_get_error(), default_msg);
838 }
839
840 return ManagedEVPPKey(std::move(pkey));
841}
842
843KeyObjectData::KeyObjectData(
844 ByteSource symmetric_key)
845 : key_type_(KeyType::kKeyTypeSecret),
846 symmetric_key_(std::move(symmetric_key)),
847 symmetric_key_len_(symmetric_key_.size()),
848 asymmetric_key_() {}
849
850KeyObjectData::KeyObjectData(
851 KeyType type,
852 const ManagedEVPPKey& pkey)
853 : key_type_(type),
854 symmetric_key_(),
855 symmetric_key_len_(0),
856 asymmetric_key_{pkey} {}
857
858void KeyObjectData::MemoryInfo(MemoryTracker* tracker) const {
859 switch (GetKeyType()) {
860 case kKeyTypeSecret:
861 tracker->TrackFieldWithSize("symmetric_key", symmetric_key_.size());
862 break;
863 case kKeyTypePrivate:
864 // Fall through
865 case kKeyTypePublic:
866 tracker->TrackFieldWithSize("key", asymmetric_key_);
867 break;
868 default:
869 UNREACHABLE()do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "869", "\"Unreachable code reached\"", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0)
;
870 }
871}
872
873std::shared_ptr<KeyObjectData> KeyObjectData::CreateSecret(ByteSource key) {
874 CHECK(key)do { if (__builtin_expect(!!(!(key)), 0)) { do { static const
node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":"
"874", "key", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
;
875 return std::shared_ptr<KeyObjectData>(new KeyObjectData(std::move(key)));
876}
877
878std::shared_ptr<KeyObjectData> KeyObjectData::CreateAsymmetric(
879 KeyType key_type,
880 const ManagedEVPPKey& pkey) {
881 CHECK(pkey)do { if (__builtin_expect(!!(!(pkey)), 0)) { do { static const
node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":"
"881", "pkey", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
;
882 return std::shared_ptr<KeyObjectData>(new KeyObjectData(key_type, pkey));
883}
884
885KeyType KeyObjectData::GetKeyType() const {
886 return key_type_;
887}
888
889ManagedEVPPKey KeyObjectData::GetAsymmetricKey() const {
890 CHECK_NE(key_type_, kKeyTypeSecret)do { if (__builtin_expect(!!(!((key_type_) != (kKeyTypeSecret
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "890", "(key_type_) != (kKeyTypeSecret)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
891 return asymmetric_key_;
892}
893
894const char* KeyObjectData::GetSymmetricKey() const {
895 CHECK_EQ(key_type_, kKeyTypeSecret)do { if (__builtin_expect(!!(!((key_type_) == (kKeyTypeSecret
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "895", "(key_type_) == (kKeyTypeSecret)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
896 return symmetric_key_.data<char>();
897}
898
899size_t KeyObjectData::GetSymmetricKeySize() const {
900 CHECK_EQ(key_type_, kKeyTypeSecret)do { if (__builtin_expect(!!(!((key_type_) == (kKeyTypeSecret
))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "900", "(key_type_) == (kKeyTypeSecret)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
901 return symmetric_key_len_;
902}
903
904v8::Local<v8::Function> KeyObjectHandle::Initialize(Environment* env) {
905 Local<Function> templ = env->crypto_key_object_handle_constructor();
906 if (!templ.IsEmpty()) {
907 return templ;
908 }
909 Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
910 t->InstanceTemplate()->SetInternalFieldCount(
911 KeyObjectHandle::kInternalFieldCount);
912 t->Inherit(BaseObject::GetConstructorTemplate(env));
913
914 env->SetProtoMethod(t, "init", Init);
915 env->SetProtoMethodNoSideEffect(t, "getSymmetricKeySize",
916 GetSymmetricKeySize);
917 env->SetProtoMethodNoSideEffect(t, "getAsymmetricKeyType",
918 GetAsymmetricKeyType);
919 env->SetProtoMethod(t, "export", Export);
920 env->SetProtoMethod(t, "exportJwk", ExportJWK);
921 env->SetProtoMethod(t, "initECRaw", InitECRaw);
922 env->SetProtoMethod(t, "initEDRaw", InitEDRaw);
923 env->SetProtoMethod(t, "initJwk", InitJWK);
924 env->SetProtoMethod(t, "keyDetail", GetKeyDetail);
925 env->SetProtoMethod(t, "equals", Equals);
926
927 auto function = t->GetFunction(env->context()).ToLocalChecked();
928 env->set_crypto_key_object_handle_constructor(function);
929 return function;
930}
931
932void KeyObjectHandle::RegisterExternalReferences(
933 ExternalReferenceRegistry* registry) {
934 registry->Register(New);
935 registry->Register(Init);
936 registry->Register(GetSymmetricKeySize);
937 registry->Register(GetAsymmetricKeyType);
938 registry->Register(Export);
939 registry->Register(ExportJWK);
940 registry->Register(InitECRaw);
941 registry->Register(InitEDRaw);
942 registry->Register(InitJWK);
943 registry->Register(GetKeyDetail);
944 registry->Register(Equals);
945}
946
947MaybeLocal<Object> KeyObjectHandle::Create(
948 Environment* env,
949 std::shared_ptr<KeyObjectData> data) {
950 Local<Object> obj;
951 Local<Function> ctor = KeyObjectHandle::Initialize(env);
952 CHECK(!env->crypto_key_object_handle_constructor().IsEmpty())do { if (__builtin_expect(!!(!(!env->crypto_key_object_handle_constructor
().IsEmpty())), 0)) { do { static const node::AssertionInfo args
= { "../src/crypto/crypto_keys.cc" ":" "952", "!env->crypto_key_object_handle_constructor().IsEmpty()"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
953 if (!ctor->NewInstance(env->context(), 0, nullptr).ToLocal(&obj))
954 return MaybeLocal<Object>();
955
956 KeyObjectHandle* key = Unwrap<KeyObjectHandle>(obj);
957 CHECK_NOT_NULL(key)do { if (__builtin_expect(!!(!((key) != nullptr)), 0)) { do {
static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "957", "(key) != nullptr", __PRETTY_FUNCTION__ }; node::
Assert(args); } while (0); } } while (0)
;
958 key->data_ = data;
959 return obj;
960}
961
962const std::shared_ptr<KeyObjectData>& KeyObjectHandle::Data() {
963 return data_;
964}
965
966void KeyObjectHandle::New(const FunctionCallbackInfo<Value>& args) {
967 CHECK(args.IsConstructCall())do { if (__builtin_expect(!!(!(args.IsConstructCall())), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "967", "args.IsConstructCall()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
968 Environment* env = Environment::GetCurrent(args);
969 new KeyObjectHandle(env, args.This());
970}
971
972KeyObjectHandle::KeyObjectHandle(Environment* env,
973 Local<Object> wrap)
974 : BaseObject(env, wrap) {
975 MakeWeak();
976}
977
978void KeyObjectHandle::Init(const FunctionCallbackInfo<Value>& args) {
979 KeyObjectHandle* key;
980 ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference
<decltype(*&key)>::type>( BaseObject::FromJSObject
(args.Holder())); if (*&key == nullptr) return ; } while (
0)
;
1
Assuming the condition is false
2
Taking false branch
3
Loop condition is false. Exiting loop
981 MarkPopErrorOnReturn mark_pop_error_on_return;
982
983 CHECK(args[0]->IsInt32())do { if (__builtin_expect(!!(!(args[0]->IsInt32())), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "983", "args[0]->IsInt32()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
4
Assuming the condition is false
5
Taking false branch
6
Loop condition is false. Exiting loop
984 KeyType type = static_cast<KeyType>(args[0].As<Uint32>()->Value());
985
986 unsigned int offset;
987 ManagedEVPPKey pkey;
988
989 switch (type) {
7
Control jumps to 'case kKeyTypePrivate:' at line 1006
990 case kKeyTypeSecret: {
991 CHECK_EQ(args.Length(), 2)do { if (__builtin_expect(!!(!((args.Length()) == (2))), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "991", "(args.Length()) == (2)", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
992 ArrayBufferOrViewContents<char> buf(args[1]);
993 key->data_ = KeyObjectData::CreateSecret(buf.ToCopy());
994 break;
995 }
996 case kKeyTypePublic: {
997 CHECK_EQ(args.Length(), 5)do { if (__builtin_expect(!!(!((args.Length()) == (5))), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "997", "(args.Length()) == (5)", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
998
999 offset = 1;
1000 pkey = ManagedEVPPKey::GetPublicOrPrivateKeyFromJs(args, &offset);
1001 if (!pkey)
1002 return;
1003 key->data_ = KeyObjectData::CreateAsymmetric(type, pkey);
1004 break;
1005 }
1006 case kKeyTypePrivate: {
1007 CHECK_EQ(args.Length(), 5)do { if (__builtin_expect(!!(!((args.Length()) == (5))), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1007", "(args.Length()) == (5)", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
8
Assuming the condition is true
9
Taking false branch
10
Loop condition is false. Exiting loop
1008
1009 offset = 1;
1010 pkey = ManagedEVPPKey::GetPrivateKeyFromJs(args, &offset, false);
11
Calling 'ManagedEVPPKey::GetPrivateKeyFromJs'
1011 if (!pkey)
1012 return;
1013 key->data_ = KeyObjectData::CreateAsymmetric(type, pkey);
1014 break;
1015 }
1016 default:
1017 UNREACHABLE()do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1017", "\"Unreachable code reached\"", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0)
;
1018 }
1019}
1020
1021void KeyObjectHandle::InitJWK(const FunctionCallbackInfo<Value>& args) {
1022 Environment* env = Environment::GetCurrent(args);
1023 KeyObjectHandle* key;
1024 ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference
<decltype(*&key)>::type>( BaseObject::FromJSObject
(args.Holder())); if (*&key == nullptr) return ; } while (
0)
;
1025 MarkPopErrorOnReturn mark_pop_error_on_return;
1026
1027 // The argument must be a JavaScript object that we will inspect
1028 // to get the JWK properties from.
1029 CHECK(args[0]->IsObject())do { if (__builtin_expect(!!(!(args[0]->IsObject())), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1029", "args[0]->IsObject()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1030
1031 // Step one, Secret key or not?
1032 Local<Object> input = args[0].As<Object>();
1033
1034 Local<Value> kty;
1035 if (!input->Get(env->context(), env->jwk_kty_string()).ToLocal(&kty) ||
1036 !kty->IsString()) {
1037 return THROW_ERR_CRYPTO_INVALID_JWK(env);
1038 }
1039
1040 Utf8Value kty_string(env->isolate(), kty);
1041
1042 if (strcmp(*kty_string, "oct") == 0) {
1043 // Secret key
1044 key->data_ = ImportJWKSecretKey(env, input);
1045 if (!key->data_) {
1046 // ImportJWKSecretKey is responsible for throwing an appropriate error
1047 return;
1048 }
1049 } else {
1050 key->data_ = ImportJWKAsymmetricKey(env, input, *kty_string, args, 1);
1051 if (!key->data_) {
1052 // ImportJWKAsymmetricKey is responsible for throwing an appropriate error
1053 return;
1054 }
1055 }
1056
1057 args.GetReturnValue().Set(key->data_->GetKeyType());
1058}
1059
1060void KeyObjectHandle::InitECRaw(const FunctionCallbackInfo<Value>& args) {
1061 Environment* env = Environment::GetCurrent(args);
1062 KeyObjectHandle* key;
1063 ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference
<decltype(*&key)>::type>( BaseObject::FromJSObject
(args.Holder())); if (*&key == nullptr) return ; } while (
0)
;
1064
1065 CHECK(args[0]->IsString())do { if (__builtin_expect(!!(!(args[0]->IsString())), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1065", "args[0]->IsString()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1066 Utf8Value name(env->isolate(), args[0]);
1067
1068 MarkPopErrorOnReturn mark_pop_error_on_return;
1069
1070 int id = OBJ_txt2nid(*name);
1071 ECKeyPointer eckey(EC_KEY_new_by_curve_name(id));
1072 if (!eckey)
1073 return args.GetReturnValue().Set(false);
1074
1075 const EC_GROUP* group = EC_KEY_get0_group(eckey.get());
1076 ECPointPointer pub(ECDH::BufferToPoint(env, group, args[1]));
1077
1078 if (!pub ||
1079 !eckey ||
1080 !EC_KEY_set_public_key(eckey.get(), pub.get())) {
1081 return args.GetReturnValue().Set(false);
1082 }
1083
1084 EVPKeyPointer pkey(EVP_PKEY_new());
1085 if (!EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get())EVP_PKEY_assign((pkey.get()), 408, (eckey.get())))
1086 args.GetReturnValue().Set(false);
1087
1088 eckey.release(); // Release ownership of the key
1089
1090 key->data_ =
1091 KeyObjectData::CreateAsymmetric(
1092 kKeyTypePublic,
1093 ManagedEVPPKey(std::move(pkey)));
1094
1095 args.GetReturnValue().Set(true);
1096}
1097
1098void KeyObjectHandle::InitEDRaw(const FunctionCallbackInfo<Value>& args) {
1099 Environment* env = Environment::GetCurrent(args);
1100 KeyObjectHandle* key;
1101 ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference
<decltype(*&key)>::type>( BaseObject::FromJSObject
(args.Holder())); if (*&key == nullptr) return ; } while (
0)
;
1102
1103 CHECK(args[0]->IsString())do { if (__builtin_expect(!!(!(args[0]->IsString())), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1103", "args[0]->IsString()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1104 Utf8Value name(env->isolate(), args[0]);
1105
1106 ArrayBufferOrViewContents<unsigned char> key_data(args[1]);
1107 KeyType type = static_cast<KeyType>(args[2].As<Int32>()->Value());
1108
1109 MarkPopErrorOnReturn mark_pop_error_on_return;
1110
1111 typedef EVP_PKEY* (*new_key_fn)(int, ENGINE*, const unsigned char*, size_t);
1112 new_key_fn fn = type == kKeyTypePrivate
1113 ? EVP_PKEY_new_raw_private_key
1114 : EVP_PKEY_new_raw_public_key;
1115
1116 int id = GetOKPCurveFromName(*name);
1117
1118 switch (id) {
1119 case EVP_PKEY_X255191034:
1120 case EVP_PKEY_X4481035:
1121 case EVP_PKEY_ED255191087:
1122 case EVP_PKEY_ED4481088: {
1123 EVPKeyPointer pkey(fn(id, nullptr, key_data.data(), key_data.size()));
1124 if (!pkey)
1125 return args.GetReturnValue().Set(false);
1126 key->data_ =
1127 KeyObjectData::CreateAsymmetric(
1128 type,
1129 ManagedEVPPKey(std::move(pkey)));
1130 CHECK(key->data_)do { if (__builtin_expect(!!(!(key->data_)), 0)) { do { static
const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1130", "key->data_", __PRETTY_FUNCTION__ }; node::Assert
(args); } while (0); } } while (0)
;
1131 break;
1132 }
1133 default:
1134 UNREACHABLE()do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1134", "\"Unreachable code reached\"", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0)
;
1135 }
1136
1137 args.GetReturnValue().Set(true);
1138}
1139
1140void KeyObjectHandle::Equals(const FunctionCallbackInfo<Value>& args) {
1141 KeyObjectHandle* self_handle;
1142 KeyObjectHandle* arg_handle;
1143 ASSIGN_OR_RETURN_UNWRAP(&self_handle, args.Holder())do { *&self_handle = static_cast<typename std::remove_reference
<decltype(*&self_handle)>::type>( BaseObject::FromJSObject
(args.Holder())); if (*&self_handle == nullptr) return ; }
while (0)
;
1144 ASSIGN_OR_RETURN_UNWRAP(&arg_handle, args[0].As<Object>())do { *&arg_handle = static_cast<typename std::remove_reference
<decltype(*&arg_handle)>::type>( BaseObject::FromJSObject
(args[0].As<Object>())); if (*&arg_handle == nullptr
) return ; } while (0)
;
1145 std::shared_ptr<KeyObjectData> key = self_handle->Data();
1146 std::shared_ptr<KeyObjectData> key2 = arg_handle->Data();
1147
1148 KeyType key_type = key->GetKeyType();
1149 CHECK_EQ(key_type, key2->GetKeyType())do { if (__builtin_expect(!!(!((key_type) == (key2->GetKeyType
()))), 0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1149", "(key_type) == (key2->GetKeyType())", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
1150
1151 bool ret;
1152 switch (key_type) {
1153 case kKeyTypeSecret: {
1154 size_t size = key->GetSymmetricKeySize();
1155 if (size == key2->GetSymmetricKeySize()) {
1156 ret = CRYPTO_memcmp(
1157 key->GetSymmetricKey(),
1158 key2->GetSymmetricKey(),
1159 size) == 0;
1160 } else {
1161 ret = false;
1162 }
1163 break;
1164 }
1165 case kKeyTypePublic:
1166 case kKeyTypePrivate: {
1167 EVP_PKEY* pkey = key->GetAsymmetricKey().get();
1168 EVP_PKEY* pkey2 = key2->GetAsymmetricKey().get();
1169#if OPENSSL_VERSION_MAJOR3 >= 3
1170 int ok = EVP_PKEY_eq(pkey, pkey2);
1171#else
1172 int ok = EVP_PKEY_cmp(pkey, pkey2);
1173#endif
1174 if (ok == -2) {
1175 Environment* env = Environment::GetCurrent(args);
1176 return THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env);
1177 }
1178 ret = ok == 1;
1179 break;
1180 }
1181 default:
1182 UNREACHABLE("unsupported key type")do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1182", "\"Unreachable code reached\" \": \" \"unsupported key type\""
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0)
;
1183 }
1184
1185 args.GetReturnValue().Set(ret);
1186}
1187
1188void KeyObjectHandle::GetKeyDetail(const FunctionCallbackInfo<Value>& args) {
1189 Environment* env = Environment::GetCurrent(args);
1190 KeyObjectHandle* key;
1191 ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference
<decltype(*&key)>::type>( BaseObject::FromJSObject
(args.Holder())); if (*&key == nullptr) return ; } while (
0)
;
1192
1193 CHECK(args[0]->IsObject())do { if (__builtin_expect(!!(!(args[0]->IsObject())), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1193", "args[0]->IsObject()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1194
1195 std::shared_ptr<KeyObjectData> data = key->Data();
1196
1197 switch (data->GetKeyType()) {
1198 case kKeyTypeSecret:
1199 if (GetSecretKeyDetail(env, data, args[0].As<Object>()).IsNothing())
1200 return;
1201 break;
1202 case kKeyTypePublic:
1203 // Fall through
1204 case kKeyTypePrivate:
1205 if (GetAsymmetricKeyDetail(env, data, args[0].As<Object>()).IsNothing())
1206 return;
1207 break;
1208 default:
1209 UNREACHABLE()do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1209", "\"Unreachable code reached\"", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0)
;
1210 }
1211
1212 args.GetReturnValue().Set(args[0]);
1213}
1214
1215Local<Value> KeyObjectHandle::GetAsymmetricKeyType() const {
1216 const ManagedEVPPKey& key = data_->GetAsymmetricKey();
1217 switch (EVP_PKEY_idEVP_PKEY_get_id(key.get())) {
1218 case EVP_PKEY_RSA6:
1219 return env()->crypto_rsa_string();
1220 case EVP_PKEY_RSA_PSS912:
1221 return env()->crypto_rsa_pss_string();
1222 case EVP_PKEY_DSA116:
1223 return env()->crypto_dsa_string();
1224 case EVP_PKEY_DH28:
1225 return env()->crypto_dh_string();
1226 case EVP_PKEY_EC408:
1227 return env()->crypto_ec_string();
1228 case EVP_PKEY_ED255191087:
1229 return env()->crypto_ed25519_string();
1230 case EVP_PKEY_ED4481088:
1231 return env()->crypto_ed448_string();
1232 case EVP_PKEY_X255191034:
1233 return env()->crypto_x25519_string();
1234 case EVP_PKEY_X4481035:
1235 return env()->crypto_x448_string();
1236 default:
1237 return Undefined(env()->isolate());
1238 }
1239}
1240
1241void KeyObjectHandle::GetAsymmetricKeyType(
1242 const FunctionCallbackInfo<Value>& args) {
1243 KeyObjectHandle* key;
1244 ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference
<decltype(*&key)>::type>( BaseObject::FromJSObject
(args.Holder())); if (*&key == nullptr) return ; } while (
0)
;
1245
1246 args.GetReturnValue().Set(key->GetAsymmetricKeyType());
1247}
1248
1249void KeyObjectHandle::GetSymmetricKeySize(
1250 const FunctionCallbackInfo<Value>& args) {
1251 KeyObjectHandle* key;
1252 ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference
<decltype(*&key)>::type>( BaseObject::FromJSObject
(args.Holder())); if (*&key == nullptr) return ; } while (
0)
;
1253 args.GetReturnValue().Set(
1254 static_cast<uint32_t>(key->Data()->GetSymmetricKeySize()));
1255}
1256
1257void KeyObjectHandle::Export(const FunctionCallbackInfo<Value>& args) {
1258 KeyObjectHandle* key;
1259 ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference
<decltype(*&key)>::type>( BaseObject::FromJSObject
(args.Holder())); if (*&key == nullptr) return ; } while (
0)
;
1260
1261 KeyType type = key->Data()->GetKeyType();
1262
1263 MaybeLocal<Value> result;
1264 if (type == kKeyTypeSecret) {
1265 result = key->ExportSecretKey();
1266 } else if (type == kKeyTypePublic) {
1267 unsigned int offset = 0;
1268 PublicKeyEncodingConfig config =
1269 ManagedEVPPKey::GetPublicKeyEncodingFromJs(
1270 args, &offset, kKeyContextExport);
1271 CHECK_EQ(offset, static_cast<unsigned int>(args.Length()))do { if (__builtin_expect(!!(!((offset) == (static_cast<unsigned
int>(args.Length())))), 0)) { do { static const node::AssertionInfo
args = { "../src/crypto/crypto_keys.cc" ":" "1271", "(offset) == (static_cast<unsigned int>(args.Length()))"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
1272 result = key->ExportPublicKey(config);
1273 } else {
1274 CHECK_EQ(type, kKeyTypePrivate)do { if (__builtin_expect(!!(!((type) == (kKeyTypePrivate))),
0)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1274", "(type) == (kKeyTypePrivate)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
1275 unsigned int offset = 0;
1276 NonCopyableMaybe<PrivateKeyEncodingConfig> config =
1277 ManagedEVPPKey::GetPrivateKeyEncodingFromJs(
1278 args, &offset, kKeyContextExport);
1279 if (config.IsEmpty())
1280 return;
1281 CHECK_EQ(offset, static_cast<unsigned int>(args.Length()))do { if (__builtin_expect(!!(!((offset) == (static_cast<unsigned
int>(args.Length())))), 0)) { do { static const node::AssertionInfo
args = { "../src/crypto/crypto_keys.cc" ":" "1281", "(offset) == (static_cast<unsigned int>(args.Length()))"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
1282 result = key->ExportPrivateKey(config.Release());
1283 }
1284
1285 if (!result.IsEmpty())
1286 args.GetReturnValue().Set(result.FromMaybe(Local<Value>()));
1287}
1288
1289MaybeLocal<Value> KeyObjectHandle::ExportSecretKey() const {
1290 const char* buf = data_->GetSymmetricKey();
1291 unsigned int len = data_->GetSymmetricKeySize();
1292 return Buffer::Copy(env(), buf, len).FromMaybe(Local<Value>());
1293}
1294
1295MaybeLocal<Value> KeyObjectHandle::ExportPublicKey(
1296 const PublicKeyEncodingConfig& config) const {
1297 return WritePublicKey(env(), data_->GetAsymmetricKey().get(), config);
1298}
1299
1300MaybeLocal<Value> KeyObjectHandle::ExportPrivateKey(
1301 const PrivateKeyEncodingConfig& config) const {
1302 return WritePrivateKey(env(), data_->GetAsymmetricKey().get(), config);
1303}
1304
1305void KeyObjectHandle::ExportJWK(
1306 const v8::FunctionCallbackInfo<v8::Value>& args) {
1307 Environment* env = Environment::GetCurrent(args);
1308 KeyObjectHandle* key;
1309 ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder())do { *&key = static_cast<typename std::remove_reference
<decltype(*&key)>::type>( BaseObject::FromJSObject
(args.Holder())); if (*&key == nullptr) return ; } while (
0)
;
1310
1311 CHECK(args[0]->IsObject())do { if (__builtin_expect(!!(!(args[0]->IsObject())), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1311", "args[0]->IsObject()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1312 CHECK(args[1]->IsBoolean())do { if (__builtin_expect(!!(!(args[1]->IsBoolean())), 0))
{ do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1312", "args[1]->IsBoolean()", __PRETTY_FUNCTION__ }
; node::Assert(args); } while (0); } } while (0)
;
1313
1314 ExportJWKInner(env, key->Data(), args[0], args[1]->IsTrue());
1315
1316 args.GetReturnValue().Set(args[0]);
1317}
1318
1319void NativeKeyObject::Initialize(Environment* env, Local<Object> target) {
1320 env->SetMethod(target, "createNativeKeyObjectClass",
1321 NativeKeyObject::CreateNativeKeyObjectClass);
1322}
1323
1324void NativeKeyObject::RegisterExternalReferences(
1325 ExternalReferenceRegistry* registry) {
1326 registry->Register(NativeKeyObject::CreateNativeKeyObjectClass);
1327 registry->Register(NativeKeyObject::New);
1328}
1329
1330void NativeKeyObject::New(const FunctionCallbackInfo<Value>& args) {
1331 Environment* env = Environment::GetCurrent(args);
1332 CHECK_EQ(args.Length(), 1)do { if (__builtin_expect(!!(!((args.Length()) == (1))), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1332", "(args.Length()) == (1)", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1333 CHECK(args[0]->IsObject())do { if (__builtin_expect(!!(!(args[0]->IsObject())), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1333", "args[0]->IsObject()", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1334 KeyObjectHandle* handle = Unwrap<KeyObjectHandle>(args[0].As<Object>());
1335 new NativeKeyObject(env, args.This(), handle->Data());
1336}
1337
1338void NativeKeyObject::CreateNativeKeyObjectClass(
1339 const FunctionCallbackInfo<Value>& args) {
1340 Environment* env = Environment::GetCurrent(args);
1341
1342 CHECK_EQ(args.Length(), 1)do { if (__builtin_expect(!!(!((args.Length()) == (1))), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1342", "(args.Length()) == (1)", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
1343 Local<Value> callback = args[0];
1344 CHECK(callback->IsFunction())do { if (__builtin_expect(!!(!(callback->IsFunction())), 0
)) { do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.cc"
":" "1344", "callback->IsFunction()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
1345
1346 Local<FunctionTemplate> t = env->NewFunctionTemplate(NativeKeyObject::New);
1347 t->InstanceTemplate()->SetInternalFieldCount(
1348 KeyObjectHandle::kInternalFieldCount);
1349 t->Inherit(BaseObject::GetConstructorTemplate(env));
1350
1351 Local<Value> ctor;
1352 if (!t->GetFunction(env->context()).ToLocal(&ctor))
1353 return;
1354
1355 Local<Value> recv = Undefined(env->isolate());
1356 Local<Value> ret_v;
1357 if (!callback.As<Function>()->Call(
1358 env->context(), recv, 1, &ctor).ToLocal(&ret_v)) {
1359 return;
1360 }
1361 Local<Array> ret = ret_v.As<Array>();
1362 if (!ret->Get(env->context(), 1).ToLocal(&ctor)) return;
1363 env->set_crypto_key_object_secret_constructor(ctor.As<Function>());
1364 if (!ret->Get(env->context(), 2).ToLocal(&ctor)) return;
1365 env->set_crypto_key_object_public_constructor(ctor.As<Function>());
1366 if (!ret->Get(env->context(), 3).ToLocal(&ctor)) return;
1367 env->set_crypto_key_object_private_constructor(ctor.As<Function>());
1368 args.GetReturnValue().Set(ret);
1369}
1370
1371BaseObjectPtr<BaseObject> NativeKeyObject::KeyObjectTransferData::Deserialize(
1372 Environment* env,
1373 Local<Context> context,
1374 std::unique_ptr<worker::TransferData> self) {
1375 if (context != env->context()) {
1376 THROW_ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE(env);
1377 return {};
1378 }
1379
1380 Local<Value> handle;
1381 if (!KeyObjectHandle::Create(env, data_).ToLocal(&handle))
1382 return {};
1383
1384 Local<Function> key_ctor;
1385 Local<Value> arg = FIXED_ONE_BYTE_STRING(env->isolate(),
1386 "internal/crypto/keys");
1387 if (env->native_module_require()->
1388 Call(context, Null(env->isolate()), 1, &arg).IsEmpty()) {
1389 return {};
1390 }
1391 switch (data_->GetKeyType()) {
1392 case kKeyTypeSecret:
1393 key_ctor = env->crypto_key_object_secret_constructor();
1394 break;
1395 case kKeyTypePublic:
1396 key_ctor = env->crypto_key_object_public_constructor();
1397 break;
1398 case kKeyTypePrivate:
1399 key_ctor = env->crypto_key_object_private_constructor();
1400 break;
1401 default:
1402 CHECK(false)do { if (__builtin_expect(!!(!(false)), 0)) { do { static const
node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":"
"1402", "false", __PRETTY_FUNCTION__ }; node::Assert(args); }
while (0); } } while (0)
;
1403 }
1404
1405 Local<Value> key;
1406 if (!key_ctor->NewInstance(context, 1, &handle).ToLocal(&key))
1407 return {};
1408
1409 return BaseObjectPtr<BaseObject>(Unwrap<KeyObjectHandle>(key.As<Object>()));
1410}
1411
1412BaseObject::TransferMode NativeKeyObject::GetTransferMode() const {
1413 return BaseObject::TransferMode::kCloneable;
1414}
1415
1416std::unique_ptr<worker::TransferData> NativeKeyObject::CloneForMessaging()
1417 const {
1418 return std::make_unique<KeyObjectTransferData>(handle_data_);
1419}
1420
1421WebCryptoKeyExportStatus PKEY_SPKI_Export(
1422 KeyObjectData* key_data,
1423 ByteSource* out) {
1424 CHECK_EQ(key_data->GetKeyType(), kKeyTypePublic)do { if (__builtin_expect(!!(!((key_data->GetKeyType()) ==
(kKeyTypePublic))), 0)) { do { static const node::AssertionInfo
args = { "../src/crypto/crypto_keys.cc" ":" "1424", "(key_data->GetKeyType()) == (kKeyTypePublic)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
1425 ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey();
1426 Mutex::ScopedLock lock(*m_pkey.mutex());
1427 BIOPointer bio(BIO_new(BIO_s_mem()));
1428 CHECK(bio)do { if (__builtin_expect(!!(!(bio)), 0)) { do { static const
node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":"
"1428", "bio", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
;
1429 if (!i2d_PUBKEY_bio(bio.get(), m_pkey.get()))
1430 return WebCryptoKeyExportStatus::FAILED;
1431
1432 *out = ByteSource::FromBIO(bio);
1433 return WebCryptoKeyExportStatus::OK;
1434}
1435
1436WebCryptoKeyExportStatus PKEY_PKCS8_Export(
1437 KeyObjectData* key_data,
1438 ByteSource* out) {
1439 CHECK_EQ(key_data->GetKeyType(), kKeyTypePrivate)do { if (__builtin_expect(!!(!((key_data->GetKeyType()) ==
(kKeyTypePrivate))), 0)) { do { static const node::AssertionInfo
args = { "../src/crypto/crypto_keys.cc" ":" "1439", "(key_data->GetKeyType()) == (kKeyTypePrivate)"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
1440 ManagedEVPPKey m_pkey = key_data->GetAsymmetricKey();
1441 Mutex::ScopedLock lock(*m_pkey.mutex());
1442
1443 BIOPointer bio(BIO_new(BIO_s_mem()));
1444 CHECK(bio)do { if (__builtin_expect(!!(!(bio)), 0)) { do { static const
node::AssertionInfo args = { "../src/crypto/crypto_keys.cc" ":"
"1444", "bio", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
;
1445 PKCS8Pointer p8inf(EVP_PKEY2PKCS8(m_pkey.get()));
1446 if (!i2d_PKCS8_PRIV_KEY_INFO_bio(bio.get(), p8inf.get()))
1447 return WebCryptoKeyExportStatus::FAILED;
1448
1449 *out = ByteSource::FromBIO(bio);
1450 return WebCryptoKeyExportStatus::OK;
1451}
1452
1453namespace Keys {
1454void Initialize(Environment* env, Local<Object> target) {
1455 target->Set(env->context(),
1456 FIXED_ONE_BYTE_STRING(env->isolate(), "KeyObjectHandle"),
1457 KeyObjectHandle::Initialize(env)).Check();
1458
1459 NODE_DEFINE_CONSTANT(target, kWebCryptoKeyFormatRaw)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kWebCryptoKeyFormatRaw", v8::NewStringType::kInternalized
).ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(kWebCryptoKeyFormatRaw
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1460 NODE_DEFINE_CONSTANT(target, kWebCryptoKeyFormatPKCS8)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kWebCryptoKeyFormatPKCS8", v8::NewStringType::kInternalized
).ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(kWebCryptoKeyFormatPKCS8
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1461 NODE_DEFINE_CONSTANT(target, kWebCryptoKeyFormatSPKI)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kWebCryptoKeyFormatSPKI", v8::NewStringType::kInternalized
).ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(kWebCryptoKeyFormatSPKI
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1462 NODE_DEFINE_CONSTANT(target, kWebCryptoKeyFormatJWK)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kWebCryptoKeyFormatJWK", v8::NewStringType::kInternalized
).ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(kWebCryptoKeyFormatJWK
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1463
1464 NODE_DEFINE_CONSTANT(target, EVP_PKEY_ED25519)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "EVP_PKEY_ED25519", v8::NewStringType::kInternalized
).ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(1087));
v8::PropertyAttribute constant_attributes = static_cast<v8
::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1465 NODE_DEFINE_CONSTANT(target, EVP_PKEY_ED448)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "EVP_PKEY_ED448", v8::NewStringType::kInternalized)
.ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(1088));
v8::PropertyAttribute constant_attributes = static_cast<v8
::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1466 NODE_DEFINE_CONSTANT(target, EVP_PKEY_X25519)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "EVP_PKEY_X25519", v8::NewStringType::kInternalized
).ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(1034));
v8::PropertyAttribute constant_attributes = static_cast<v8
::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1467 NODE_DEFINE_CONSTANT(target, EVP_PKEY_X448)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "EVP_PKEY_X448", v8::NewStringType::kInternalized).
ToLocalChecked(); v8::Local<v8::Number> constant_value =
v8::Number::New(isolate, static_cast<double>(1035)); v8
::PropertyAttribute constant_attributes = static_cast<v8::
PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1468 NODE_DEFINE_CONSTANT(target, kKeyEncodingPKCS1)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kKeyEncodingPKCS1", v8::NewStringType::kInternalized
).ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(kKeyEncodingPKCS1
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1469 NODE_DEFINE_CONSTANT(target, kKeyEncodingPKCS8)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kKeyEncodingPKCS8", v8::NewStringType::kInternalized
).ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(kKeyEncodingPKCS8
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1470 NODE_DEFINE_CONSTANT(target, kKeyEncodingSPKI)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kKeyEncodingSPKI", v8::NewStringType::kInternalized
).ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(kKeyEncodingSPKI
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1471 NODE_DEFINE_CONSTANT(target, kKeyEncodingSEC1)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kKeyEncodingSEC1", v8::NewStringType::kInternalized
).ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(kKeyEncodingSEC1
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1472 NODE_DEFINE_CONSTANT(target, kKeyFormatDER)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kKeyFormatDER", v8::NewStringType::kInternalized).
ToLocalChecked(); v8::Local<v8::Number> constant_value =
v8::Number::New(isolate, static_cast<double>(kKeyFormatDER
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1473 NODE_DEFINE_CONSTANT(target, kKeyFormatPEM)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kKeyFormatPEM", v8::NewStringType::kInternalized).
ToLocalChecked(); v8::Local<v8::Number> constant_value =
v8::Number::New(isolate, static_cast<double>(kKeyFormatPEM
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1474 NODE_DEFINE_CONSTANT(target, kKeyFormatJWK)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kKeyFormatJWK", v8::NewStringType::kInternalized).
ToLocalChecked(); v8::Local<v8::Number> constant_value =
v8::Number::New(isolate, static_cast<double>(kKeyFormatJWK
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1475 NODE_DEFINE_CONSTANT(target, kKeyTypeSecret)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kKeyTypeSecret", v8::NewStringType::kInternalized)
.ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(kKeyTypeSecret
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1476 NODE_DEFINE_CONSTANT(target, kKeyTypePublic)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kKeyTypePublic", v8::NewStringType::kInternalized)
.ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(kKeyTypePublic
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1477 NODE_DEFINE_CONSTANT(target, kKeyTypePrivate)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kKeyTypePrivate", v8::NewStringType::kInternalized
).ToLocalChecked(); v8::Local<v8::Number> constant_value
= v8::Number::New(isolate, static_cast<double>(kKeyTypePrivate
)); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); (target
)->DefineOwnProperty(context, constant_name, constant_value
, constant_attributes).Check(); } while (0)
;
1478 NODE_DEFINE_CONSTANT(target, kSigEncDER)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kSigEncDER", v8::NewStringType::kInternalized).ToLocalChecked
(); v8::Local<v8::Number> constant_value = v8::Number::
New(isolate, static_cast<double>(kSigEncDER)); v8::PropertyAttribute
constant_attributes = static_cast<v8::PropertyAttribute>
(v8::ReadOnly | v8::DontDelete); (target)->DefineOwnProperty
(context, constant_name, constant_value, constant_attributes)
.Check(); } while (0)
;
1479 NODE_DEFINE_CONSTANT(target, kSigEncP1363)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::Context> context = isolate->GetCurrentContext()
; v8::Local<v8::String> constant_name = v8::String::NewFromUtf8
(isolate, "kSigEncP1363", v8::NewStringType::kInternalized).ToLocalChecked
(); v8::Local<v8::Number> constant_value = v8::Number::
New(isolate, static_cast<double>(kSigEncP1363)); v8::PropertyAttribute
constant_attributes = static_cast<v8::PropertyAttribute>
(v8::ReadOnly | v8::DontDelete); (target)->DefineOwnProperty
(context, constant_name, constant_value, constant_attributes)
.Check(); } while (0)
;
1480}
1481
1482void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1483 KeyObjectHandle::RegisterExternalReferences(registry);
1484}
1485} // namespace Keys
1486
1487} // namespace crypto
1488} // namespace node

../src/util.h

1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22#ifndef SRC_UTIL_H_
23#define SRC_UTIL_H_
24
25#if defined(NODE_WANT_INTERNALS1) && NODE_WANT_INTERNALS1
26
27#include "v8.h"
28
29#include "node.h"
30
31#include <climits>
32#include <cstddef>
33#include <cstdio>
34#include <cstdlib>
35#include <cstring>
36
37#include <array>
38#include <limits>
39#include <memory>
40#include <string>
41#include <string_view>
42#include <type_traits>
43#include <set>
44#include <unordered_map>
45#include <utility>
46#include <vector>
47
48#ifdef __GNUC__4
49#define MUST_USE_RESULT__attribute__((warn_unused_result)) __attribute__((warn_unused_result))
50#else
51#define MUST_USE_RESULT__attribute__((warn_unused_result))
52#endif
53
54namespace node {
55
56// Maybe remove kPathSeparator when cpp17 is ready
57#ifdef _WIN32
58 constexpr char kPathSeparator = '\\';
59/* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */
60#define PATH_MAX_BYTES(4096) (MAX_PATH * 4)
61#else
62 constexpr char kPathSeparator = '/';
63#define PATH_MAX_BYTES(4096) (PATH_MAX4096)
64#endif
65
66// These should be used in our code as opposed to the native
67// versions as they abstract out some platform and or
68// compiler version specific functionality
69// malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
70// that the standard allows them to either return a unique pointer or a
71// nullptr for zero-sized allocation requests. Normalize by always using
72// a nullptr.
73template <typename T>
74inline T* UncheckedRealloc(T* pointer, size_t n);
75template <typename T>
76inline T* UncheckedMalloc(size_t n);
77template <typename T>
78inline T* UncheckedCalloc(size_t n);
79
80// Same things, but aborts immediately instead of returning nullptr when
81// no memory is available.
82template <typename T>
83inline T* Realloc(T* pointer, size_t n);
84template <typename T>
85inline T* Malloc(size_t n);
86template <typename T>
87inline T* Calloc(size_t n);
88
89inline char* Malloc(size_t n);
90inline char* Calloc(size_t n);
91inline char* UncheckedMalloc(size_t n);
92inline char* UncheckedCalloc(size_t n);
93
94template <typename T>
95inline T MultiplyWithOverflowCheck(T a, T b);
96
97namespace per_process {
98// Tells whether the per-process V8::Initialize() is called and
99// if it is safe to call v8::Isolate::TryGetCurrent().
100extern bool v8_initialized;
101} // namespace per_process
102
103// Used by the allocation functions when allocation fails.
104// Thin wrapper around v8::Isolate::LowMemoryNotification() that checks
105// whether V8 is initialized.
106void LowMemoryNotification();
107
108// The reason that Assert() takes a struct argument instead of individual
109// const char*s is to ease instruction cache pressure in calls from CHECK.
110struct AssertionInfo {
111 const char* file_line; // filename:line
112 const char* message;
113 const char* function;
114};
115[[noreturn]] void NODE_EXTERN_PRIVATE Assert(const AssertionInfo& info);
116[[noreturn]] void NODE_EXTERN_PRIVATE Abort();
117void DumpBacktrace(FILE* fp);
118
119// Windows 8+ does not like abort() in Release mode
120#ifdef _WIN32
121#define ABORT_NO_BACKTRACE()abort() _exit(134)
122#else
123#define ABORT_NO_BACKTRACE()abort() abort()
124#endif
125
126#define ABORT()node::Abort() node::Abort()
127
128#define ERROR_AND_ABORT(expr)do { static const node::AssertionInfo args = { "../src/util.h"
":" "128", "expr", __PRETTY_FUNCTION__ }; node::Assert(args)
; } while (0)
\
129 do { \
130 /* Make sure that this struct does not end up in inline code, but */ \
131 /* rather in a read-only data section when modifying this code. */ \
132 static const node::AssertionInfo args = { \
133 __FILE__"../src/util.h" ":" STRINGIFY(__LINE__)"133", #expr, PRETTY_FUNCTION_NAME__PRETTY_FUNCTION__ \
134 }; \
135 node::Assert(args); \
136 } while (0)
137
138#ifdef __GNUC__4
139#define LIKELY(expr)__builtin_expect(!!(expr), 1) __builtin_expect(!!(expr), 1)
140#define UNLIKELY(expr)__builtin_expect(!!(expr), 0) __builtin_expect(!!(expr), 0)
141#define PRETTY_FUNCTION_NAME__PRETTY_FUNCTION__ __PRETTY_FUNCTION__
142#else
143#define LIKELY(expr)__builtin_expect(!!(expr), 1) expr
144#define UNLIKELY(expr)__builtin_expect(!!(expr), 0) expr
145#define PRETTY_FUNCTION_NAME__PRETTY_FUNCTION__ ""
146#endif
147
148#define STRINGIFY_(x)"x" #x
149#define STRINGIFY(x)"x" STRINGIFY_(x)"x"
150
151#define CHECK(expr)do { if (__builtin_expect(!!(!(expr)), 0)) { do { static const
node::AssertionInfo args = { "../src/util.h" ":" "151", "expr"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
\
152 do { \
153 if (UNLIKELY(!(expr))__builtin_expect(!!(!(expr)), 0)) { \
154 ERROR_AND_ABORT(expr)do { static const node::AssertionInfo args = { "../src/util.h"
":" "154", "expr", __PRETTY_FUNCTION__ }; node::Assert(args)
; } while (0)
; \
155 } \
156 } while (0)
157
158#define CHECK_EQ(a, b)do { if (__builtin_expect(!!(!((a) == (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "158"
, "(a) == (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
CHECK((a) == (b))do { if (__builtin_expect(!!(!((a) == (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "158"
, "(a) == (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
159#define CHECK_GE(a, b)do { if (__builtin_expect(!!(!((a) >= (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "159"
, "(a) >= (b)", __PRETTY_FUNCTION__ }; node::Assert(args);
} while (0); } } while (0)
CHECK((a) >= (b))do { if (__builtin_expect(!!(!((a) >= (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "159"
, "(a) >= (b)", __PRETTY_FUNCTION__ }; node::Assert(args);
} while (0); } } while (0)
160#define CHECK_GT(a, b)do { if (__builtin_expect(!!(!((a) > (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "160"
, "(a) > (b)", __PRETTY_FUNCTION__ }; node::Assert(args); }
while (0); } } while (0)
CHECK((a) > (b))do { if (__builtin_expect(!!(!((a) > (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "160"
, "(a) > (b)", __PRETTY_FUNCTION__ }; node::Assert(args); }
while (0); } } while (0)
161#define CHECK_LE(a, b)do { if (__builtin_expect(!!(!((a) <= (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "161"
, "(a) <= (b)", __PRETTY_FUNCTION__ }; node::Assert(args);
} while (0); } } while (0)
CHECK((a) <= (b))do { if (__builtin_expect(!!(!((a) <= (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "161"
, "(a) <= (b)", __PRETTY_FUNCTION__ }; node::Assert(args);
} while (0); } } while (0)
162#define CHECK_LT(a, b)do { if (__builtin_expect(!!(!((a) < (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "162"
, "(a) < (b)", __PRETTY_FUNCTION__ }; node::Assert(args); }
while (0); } } while (0)
CHECK((a) < (b))do { if (__builtin_expect(!!(!((a) < (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "162"
, "(a) < (b)", __PRETTY_FUNCTION__ }; node::Assert(args); }
while (0); } } while (0)
163#define CHECK_NE(a, b)do { if (__builtin_expect(!!(!((a) != (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "163"
, "(a) != (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
CHECK((a) != (b))do { if (__builtin_expect(!!(!((a) != (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "163"
, "(a) != (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
164#define CHECK_NULL(val)do { if (__builtin_expect(!!(!((val) == nullptr)), 0)) { do {
static const node::AssertionInfo args = { "../src/util.h" ":"
"164", "(val) == nullptr", __PRETTY_FUNCTION__ }; node::Assert
(args); } while (0); } } while (0)
CHECK((val) == nullptr)do { if (__builtin_expect(!!(!((val) == nullptr)), 0)) { do {
static const node::AssertionInfo args = { "../src/util.h" ":"
"164", "(val) == nullptr", __PRETTY_FUNCTION__ }; node::Assert
(args); } while (0); } } while (0)
165#define CHECK_NOT_NULL(val)do { if (__builtin_expect(!!(!((val) != nullptr)), 0)) { do {
static const node::AssertionInfo args = { "../src/util.h" ":"
"165", "(val) != nullptr", __PRETTY_FUNCTION__ }; node::Assert
(args); } while (0); } } while (0)
CHECK((val) != nullptr)do { if (__builtin_expect(!!(!((val) != nullptr)), 0)) { do {
static const node::AssertionInfo args = { "../src/util.h" ":"
"165", "(val) != nullptr", __PRETTY_FUNCTION__ }; node::Assert
(args); } while (0); } } while (0)
166#define CHECK_IMPLIES(a, b)do { if (__builtin_expect(!!(!(!(a) || (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "166"
, "!(a) || (b)", __PRETTY_FUNCTION__ }; node::Assert(args); }
while (0); } } while (0)
CHECK(!(a) || (b))do { if (__builtin_expect(!!(!(!(a) || (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "166"
, "!(a) || (b)", __PRETTY_FUNCTION__ }; node::Assert(args); }
while (0); } } while (0)
167
168#ifdef DEBUG
169 #define DCHECK(expr) CHECK(expr)do { if (__builtin_expect(!!(!(expr)), 0)) { do { static const
node::AssertionInfo args = { "../src/util.h" ":" "169", "expr"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
170 #define DCHECK_EQ(a, b) CHECK((a) == (b))do { if (__builtin_expect(!!(!((a) == (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "170"
, "(a) == (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
171 #define DCHECK_GE(a, b) CHECK((a) >= (b))do { if (__builtin_expect(!!(!((a) >= (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "171"
, "(a) >= (b)", __PRETTY_FUNCTION__ }; node::Assert(args);
} while (0); } } while (0)
172 #define DCHECK_GT(a, b) CHECK((a) > (b))do { if (__builtin_expect(!!(!((a) > (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "172"
, "(a) > (b)", __PRETTY_FUNCTION__ }; node::Assert(args); }
while (0); } } while (0)
173 #define DCHECK_LE(a, b) CHECK((a) <= (b))do { if (__builtin_expect(!!(!((a) <= (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "173"
, "(a) <= (b)", __PRETTY_FUNCTION__ }; node::Assert(args);
} while (0); } } while (0)
174 #define DCHECK_LT(a, b) CHECK((a) < (b))do { if (__builtin_expect(!!(!((a) < (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "174"
, "(a) < (b)", __PRETTY_FUNCTION__ }; node::Assert(args); }
while (0); } } while (0)
175 #define DCHECK_NE(a, b) CHECK((a) != (b))do { if (__builtin_expect(!!(!((a) != (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "175"
, "(a) != (b)", __PRETTY_FUNCTION__ }; node::Assert(args); } while
(0); } } while (0)
176 #define DCHECK_NULL(val) CHECK((val) == nullptr)do { if (__builtin_expect(!!(!((val) == nullptr)), 0)) { do {
static const node::AssertionInfo args = { "../src/util.h" ":"
"176", "(val) == nullptr", __PRETTY_FUNCTION__ }; node::Assert
(args); } while (0); } } while (0)
177 #define DCHECK_NOT_NULL(val) CHECK((val) != nullptr)do { if (__builtin_expect(!!(!((val) != nullptr)), 0)) { do {
static const node::AssertionInfo args = { "../src/util.h" ":"
"177", "(val) != nullptr", __PRETTY_FUNCTION__ }; node::Assert
(args); } while (0); } } while (0)
178 #define DCHECK_IMPLIES(a, b) CHECK(!(a) || (b))do { if (__builtin_expect(!!(!(!(a) || (b))), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "178"
, "!(a) || (b)", __PRETTY_FUNCTION__ }; node::Assert(args); }
while (0); } } while (0)
179#else
180 #define DCHECK(expr)
181 #define DCHECK_EQ(a, b)
182 #define DCHECK_GE(a, b)
183 #define DCHECK_GT(a, b)
184 #define DCHECK_LE(a, b)
185 #define DCHECK_LT(a, b)
186 #define DCHECK_NE(a, b)
187 #define DCHECK_NULL(val)
188 #define DCHECK_NOT_NULL(val)
189 #define DCHECK_IMPLIES(a, b)
190#endif
191
192
193#define UNREACHABLE(...)do { static const node::AssertionInfo args = { "../src/util.h"
":" "193", "\"Unreachable code reached\" \": \" ...", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0)
\
194 ERROR_AND_ABORT("Unreachable code reached" __VA_OPT__(": ") __VA_ARGS__)do { static const node::AssertionInfo args = { "../src/util.h"
":" "194", "\"Unreachable code reached\" __VA_OPT__(\": \") __VA_ARGS__"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0)
195
196// ECMA262 20.1.2.6 Number.MAX_SAFE_INTEGER (2^53-1)
197constexpr int64_t kMaxSafeJsInteger = 9007199254740991;
198
199inline bool IsSafeJsInt(v8::Local<v8::Value> v);
200
201// TAILQ-style intrusive list node.
202template <typename T>
203class ListNode;
204
205// TAILQ-style intrusive list head.
206template <typename T, ListNode<T> (T::*M)>
207class ListHead;
208
209template <typename T>
210class ListNode {
211 public:
212 inline ListNode();
213 inline ~ListNode();
214 inline void Remove();
215 inline bool IsEmpty() const;
216
217 ListNode(const ListNode&) = delete;
218 ListNode& operator=(const ListNode&) = delete;
219
220 private:
221 template <typename U, ListNode<U> (U::*M)> friend class ListHead;
222 friend int GenDebugSymbols();
223 ListNode* prev_;
224 ListNode* next_;
225};
226
227template <typename T, ListNode<T> (T::*M)>
228class ListHead {
229 public:
230 class Iterator {
231 public:
232 inline T* operator*() const;
233 inline const Iterator& operator++();
234 inline bool operator!=(const Iterator& that) const;
235
236 private:
237 friend class ListHead;
238 inline explicit Iterator(ListNode<T>* node);
239 ListNode<T>* node_;
240 };
241
242 inline ListHead() = default;
243 inline ~ListHead();
244 inline void PushBack(T* element);
245 inline void PushFront(T* element);
246 inline bool IsEmpty() const;
247 inline T* PopFront();
248 inline Iterator begin() const;
249 inline Iterator end() const;
250
251 ListHead(const ListHead&) = delete;
252 ListHead& operator=(const ListHead&) = delete;
253
254 private:
255 friend int GenDebugSymbols();
256 ListNode<T> head_;
257};
258
259// The helper is for doing safe downcasts from base types to derived types.
260template <typename Inner, typename Outer>
261class ContainerOfHelper {
262 public:
263 inline ContainerOfHelper(Inner Outer::*field, Inner* pointer);
264 template <typename TypeName>
265 inline operator TypeName*() const;
266 private:
267 Outer* const pointer_;
268};
269
270// Calculate the address of the outer (i.e. embedding) struct from
271// the interior pointer to a data member.
272template <typename Inner, typename Outer>
273constexpr ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field,
274 Inner* pointer);
275
276// Convenience wrapper around v8::String::NewFromOneByte().
277inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
278 const char* data,
279 int length = -1);
280
281// For the people that compile with -funsigned-char.
282inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
283 const signed char* data,
284 int length = -1);
285
286inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
287 const unsigned char* data,
288 int length = -1);
289
290// Used to be a macro, hence the uppercase name.
291template <int N>
292inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING(
293 v8::Isolate* isolate,
294 const char(&data)[N]) {
295 return OneByteString(isolate, data, N - 1);
296}
297
298template <std::size_t N>
299inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING(
300 v8::Isolate* isolate,
301 const std::array<char, N>& arr) {
302 return OneByteString(isolate, arr.data(), N - 1);
303}
304
305
306
307// Swaps bytes in place. nbytes is the number of bytes to swap and must be a
308// multiple of the word size (checked by function).
309inline void SwapBytes16(char* data, size_t nbytes);
310inline void SwapBytes32(char* data, size_t nbytes);
311inline void SwapBytes64(char* data, size_t nbytes);
312
313// tolower() is locale-sensitive. Use ToLower() instead.
314inline char ToLower(char c);
315inline std::string ToLower(const std::string& in);
316
317// toupper() is locale-sensitive. Use ToUpper() instead.
318inline char ToUpper(char c);
319inline std::string ToUpper(const std::string& in);
320
321// strcasecmp() is locale-sensitive. Use StringEqualNoCase() instead.
322inline bool StringEqualNoCase(const char* a, const char* b);
323
324// strncasecmp() is locale-sensitive. Use StringEqualNoCaseN() instead.
325inline bool StringEqualNoCaseN(const char* a, const char* b, size_t length);
326
327template <typename T, size_t N>
328constexpr size_t arraysize(const T (&)[N]) {
329 return N;
330}
331
332template <typename T, size_t N>
333constexpr size_t strsize(const T (&)[N]) {
334 return N - 1;
335}
336
337// Allocates an array of member type T. For up to kStackStorageSize items,
338// the stack is used, otherwise malloc().
339template <typename T, size_t kStackStorageSize = 1024>
340class MaybeStackBuffer {
341 public:
342 const T* out() const {
343 return buf_;
344 }
345
346 T* out() {
347 return buf_;
348 }
349
350 // operator* for compatibility with `v8::String::(Utf8)Value`
351 T* operator*() {
352 return buf_;
353 }
354
355 const T* operator*() const {
356 return buf_;
357 }
358
359 T& operator[](size_t index) {
360 CHECK_LT(index, length())do { if (__builtin_expect(!!(!((index) < (length()))), 0))
{ do { static const node::AssertionInfo args = { "../src/util.h"
":" "360", "(index) < (length())", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
361 return buf_[index];
362 }
363
364 const T& operator[](size_t index) const {
365 CHECK_LT(index, length())do { if (__builtin_expect(!!(!((index) < (length()))), 0))
{ do { static const node::AssertionInfo args = { "../src/util.h"
":" "365", "(index) < (length())", __PRETTY_FUNCTION__ };
node::Assert(args); } while (0); } } while (0)
;
366 return buf_[index];
367 }
368
369 size_t length() const {
370 return length_;
371 }
372
373 // Current maximum capacity of the buffer with which SetLength() can be used
374 // without first calling AllocateSufficientStorage().
375 size_t capacity() const {
376 return capacity_;
377 }
378
379 // Make sure enough space for `storage` entries is available.
380 // This method can be called multiple times throughout the lifetime of the
381 // buffer, but once this has been called Invalidate() cannot be used.
382 // Content of the buffer in the range [0, length()) is preserved.
383 void AllocateSufficientStorage(size_t storage) {
384 CHECK(!IsInvalidated())do { if (__builtin_expect(!!(!(!IsInvalidated())), 0)) { do {
static const node::AssertionInfo args = { "../src/util.h" ":"
"384", "!IsInvalidated()", __PRETTY_FUNCTION__ }; node::Assert
(args); } while (0); } } while (0)
;
385 if (storage > capacity()) {
386 bool was_allocated = IsAllocated();
387 T* allocated_ptr = was_allocated ? buf_ : nullptr;
388 buf_ = Realloc(allocated_ptr, storage);
389 capacity_ = storage;
390 if (!was_allocated && length_ > 0)
391 memcpy(buf_, buf_st_, length_ * sizeof(buf_[0]));
392 }
393
394 length_ = storage;
395 }
396
397 void SetLength(size_t length) {
398 // capacity() returns how much memory is actually available.
399 CHECK_LE(length, capacity())do { if (__builtin_expect(!!(!((length) <= (capacity()))),
0)) { do { static const node::AssertionInfo args = { "../src/util.h"
":" "399", "(length) <= (capacity())", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
400 length_ = length;
401 }
402
403 void SetLengthAndZeroTerminate(size_t length) {
404 // capacity() returns how much memory is actually available.
405 CHECK_LE(length + 1, capacity())do { if (__builtin_expect(!!(!((length + 1) <= (capacity()
))), 0)) { do { static const node::AssertionInfo args = { "../src/util.h"
":" "405", "(length + 1) <= (capacity())", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
406 SetLength(length);
407
408 // T() is 0 for integer types, nullptr for pointers, etc.
409 buf_[length] = T();
410 }
411
412 // Make dereferencing this object return nullptr.
413 // This method can be called multiple times throughout the lifetime of the
414 // buffer, but once this has been called AllocateSufficientStorage() cannot
415 // be used.
416 void Invalidate() {
417 CHECK(!IsAllocated())do { if (__builtin_expect(!!(!(!IsAllocated())), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "417"
, "!IsAllocated()", __PRETTY_FUNCTION__ }; node::Assert(args)
; } while (0); } } while (0)
;
418 capacity_ = 0;
419 length_ = 0;
420 buf_ = nullptr;
421 }
422
423 // If the buffer is stored in the heap rather than on the stack.
424 bool IsAllocated() const {
425 return !IsInvalidated() && buf_ != buf_st_;
426 }
427
428 // If Invalidate() has been called.
429 bool IsInvalidated() const {
430 return buf_ == nullptr;
431 }
432
433 // Release ownership of the malloc'd buffer.
434 // Note: This does not free the buffer.
435 void Release() {
436 CHECK(IsAllocated())do { if (__builtin_expect(!!(!(IsAllocated())), 0)) { do { static
const node::AssertionInfo args = { "../src/util.h" ":" "436"
, "IsAllocated()", __PRETTY_FUNCTION__ }; node::Assert(args);
} while (0); } } while (0)
;
437 buf_ = buf_st_;
438 length_ = 0;
439 capacity_ = arraysize(buf_st_);
440 }
441
442 MaybeStackBuffer()
443 : length_(0), capacity_(arraysize(buf_st_)), buf_(buf_st_) {
444 // Default to a zero-length, null-terminated buffer.
445 buf_[0] = T();
446 }
447
448 explicit MaybeStackBuffer(size_t storage) : MaybeStackBuffer() {
449 AllocateSufficientStorage(storage);
450 }
451
452 ~MaybeStackBuffer() {
453 if (IsAllocated())
454 free(buf_);
455 }
456
457 private:
458 size_t length_;
459 // capacity of the malloc'ed buf_
460 size_t capacity_;
461 T* buf_;
462 T buf_st_[kStackStorageSize];
463};
464
465// Provides access to an ArrayBufferView's storage, either the original,
466// or for small data, a copy of it. This object's lifetime is bound to the
467// original ArrayBufferView's lifetime.
468template <typename T, size_t kStackStorageSize = 64>
469class ArrayBufferViewContents {
470 public:
471 ArrayBufferViewContents() = default;
472
473 explicit inline ArrayBufferViewContents(v8::Local<v8::Value> value);
474 explicit inline ArrayBufferViewContents(v8::Local<v8::Object> value);
475 explicit inline ArrayBufferViewContents(v8::Local<v8::ArrayBufferView> abv);
476 inline void Read(v8::Local<v8::ArrayBufferView> abv);
477
478 inline const T* data() const { return data_; }
479 inline size_t length() const { return length_; }
480
481 private:
482 T stack_storage_[kStackStorageSize];
483 T* data_ = nullptr;
484 size_t length_ = 0;
485};
486
487class Utf8Value : public MaybeStackBuffer<char> {
488 public:
489 explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value);
490
491 inline std::string ToString() const { return std::string(out(), length()); }
492
493 inline bool operator==(const char* a) const {
494 return strcmp(out(), a) == 0;
495 }
496};
497
498class TwoByteValue : public MaybeStackBuffer<uint16_t> {
499 public:
500 explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
501};
502
503class BufferValue : public MaybeStackBuffer<char> {
504 public:
505 explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
506
507 inline std::string ToString() const { return std::string(out(), length()); }
508};
509
510#define SPREAD_BUFFER_ARG(val, name)do { if (__builtin_expect(!!(!((val)->IsArrayBufferView())
), 0)) { do { static const node::AssertionInfo args = { "../src/util.h"
":" "510", "(val)->IsArrayBufferView()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0); v8::Local
<v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView
>(); std::shared_ptr<v8::BackingStore> name_bs = name
->Buffer()->GetBackingStore(); const size_t name_offset
= name->ByteOffset(); const size_t name_length = name->
ByteLength(); char* const name_data = static_cast<char*>
(name_bs->Data()) + name_offset; if (name_length > 0) do
{ if (__builtin_expect(!!(!((name_data) != (nullptr))), 0)) {
do { static const node::AssertionInfo args = { "../src/util.h"
":" "510", "(name_data) != (nullptr)", __PRETTY_FUNCTION__ }
; node::Assert(args); } while (0); } } while (0);
\
511 CHECK((val)->IsArrayBufferView())do { if (__builtin_expect(!!(!((val)->IsArrayBufferView())
), 0)) { do { static const node::AssertionInfo args = { "../src/util.h"
":" "511", "(val)->IsArrayBufferView()", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
; \
512 v8::Local<v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView>(); \
513 std::shared_ptr<v8::BackingStore> name##_bs = \
514 name->Buffer()->GetBackingStore(); \
515 const size_t name##_offset = name->ByteOffset(); \
516 const size_t name##_length = name->ByteLength(); \
517 char* const name##_data = \
518 static_cast<char*>(name##_bs->Data()) + name##_offset; \
519 if (name##_length > 0) \
520 CHECK_NE(name##_data, nullptr)do { if (__builtin_expect(!!(!((name##_data) != (nullptr))), 0
)) { do { static const node::AssertionInfo args = { "../src/util.h"
":" "520", "(name##_data) != (nullptr)", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0); } } while (0)
;
521
522// Use this when a variable or parameter is unused in order to explicitly
523// silence a compiler warning about that.
524template <typename T> inline void USE(T&&) {}
525
526template <typename Fn>
527struct OnScopeLeaveImpl {
528 Fn fn_;
529 bool active_;
530
531 explicit OnScopeLeaveImpl(Fn&& fn) : fn_(std::move(fn)), active_(true) {}
532 ~OnScopeLeaveImpl() { if (active_) fn_(); }
533
534 OnScopeLeaveImpl(const OnScopeLeaveImpl& other) = delete;
535 OnScopeLeaveImpl& operator=(const OnScopeLeaveImpl& other) = delete;
536 OnScopeLeaveImpl(OnScopeLeaveImpl&& other)
537 : fn_(std::move(other.fn_)), active_(other.active_) {
538 other.active_ = false;
539 }
540 OnScopeLeaveImpl& operator=(OnScopeLeaveImpl&& other) {
541 if (this == &other) return *this;
542 this->~OnScopeLeave();
543 new (this)OnScopeLeaveImpl(std::move(other));
544 return *this;
545 }
546};
547
548// Run a function when exiting the current scope. Used like this:
549// auto on_scope_leave = OnScopeLeave([&] {
550// // ... run some code ...
551// });
552template <typename Fn>
553inline MUST_USE_RESULT__attribute__((warn_unused_result)) OnScopeLeaveImpl<Fn> OnScopeLeave(Fn&& fn) {
554 return OnScopeLeaveImpl<Fn>{std::move(fn)};
555}
556
557// Simple RAII wrapper for contiguous data that uses malloc()/free().
558template <typename T>
559struct MallocedBuffer {
560 T* data;
561 size_t size;
562
563 T* release() {
564 T* ret = data;
565 data = nullptr;
566 return ret;
567 }
568
569 void Truncate(size_t new_size) {
570 CHECK(new_size <= size)do { if (__builtin_expect(!!(!(new_size <= size)), 0)) { do
{ static const node::AssertionInfo args = { "../src/util.h" ":"
"570", "new_size <= size", __PRETTY_FUNCTION__ }; node::Assert
(args); } while (0); } } while (0)
;
571 size = new_size;
572 }
573
574 void Realloc(size_t new_size) {
575 Truncate(new_size);
576 data = UncheckedRealloc(data, new_size);
577 }
578
579 inline bool is_empty() const { return data == nullptr; }
580
581 MallocedBuffer() : data(nullptr), size(0) {}
582 explicit MallocedBuffer(size_t size) : data(Malloc<T>(size)), size(size) {}
583 MallocedBuffer(T* data, size_t size) : data(data), size(size) {}
584 MallocedBuffer(MallocedBuffer&& other) : data(other.data), size(other.size) {
585 other.data = nullptr;
586 }
587 MallocedBuffer& operator=(MallocedBuffer&& other) {
588 this->~MallocedBuffer();
589 return *new(this) MallocedBuffer(std::move(other));
590 }
591 ~MallocedBuffer() {
592 free(data);
593 }
594 MallocedBuffer(const MallocedBuffer&) = delete;
595 MallocedBuffer& operator=(const MallocedBuffer&) = delete;
596};
597
598template <typename T>
599class NonCopyableMaybe {
600 public:
601 NonCopyableMaybe() : empty_(true) {}
602 explicit NonCopyableMaybe(T&& value)
603 : empty_(false),
604 value_(std::move(value)) {}
21
Calling implicit move constructor for 'PrivateKeyEncodingConfig'
605
606 bool IsEmpty() const {
607 return empty_;
608 }
609
610 const T* get() const {
611 return empty_ ? nullptr : &value_;
612 }
613
614 const T* operator->() const {
615 CHECK(!empty_)do { if (__builtin_expect(!!(!(!empty_)), 0)) { do { static const
node::AssertionInfo args = { "../src/util.h" ":" "615", "!empty_"
, __PRETTY_FUNCTION__ }; node::Assert(args); } while (0); } }
while (0)
;
616 return &value_;
617 }
618
619 T&& Release() {
620 CHECK_EQ(empty_, false)do { if (__builtin_expect(!!(!((empty_) == (false))), 0)) { do
{ static const node::AssertionInfo args = { "../src/util.h" ":"
"620", "(empty_) == (false)", __PRETTY_FUNCTION__ }; node::Assert
(args); } while (0); } } while (0)
;
621 empty_ = true;
622 return std::move(value_);
623 }
624
625 private:
626 bool empty_;
627 T value_;
628};
629
630// Test whether some value can be called with ().
631template <typename T, typename = void>
632struct is_callable : std::is_function<T> { };
633
634template <typename T>
635struct is_callable<T, typename std::enable_if<
636 std::is_same<decltype(void(&T::operator())), void>::value
637 >::type> : std::true_type { };
638
639template <typename T, void (*function)(T*)>
640struct FunctionDeleter {
641 void operator()(T* pointer) const { function(pointer); }
642 typedef std::unique_ptr<T, FunctionDeleter> Pointer;
643};
644
645template <typename T, void (*function)(T*)>
646using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;
647
648std::vector<std::string> SplitString(const std::string& in,
649 char delim,
650 bool skipEmpty = true);
651
652inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
653 std::string_view str,
654 v8::Isolate* isolate = nullptr);
655template <typename T, typename test_for_number =
656 typename std::enable_if<std::numeric_limits<T>::is_specialized, bool>::type>
657inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
658 const T& number,
659 v8::Isolate* isolate = nullptr);
660template <typename T>
661inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
662 const std::vector<T>& vec,
663 v8::Isolate* isolate = nullptr);
664template <typename T>
665inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
666 const std::set<T>& set,
667 v8::Isolate* isolate = nullptr);
668template <typename T, typename U>
669inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
670 const std::unordered_map<T, U>& map,
671 v8::Isolate* isolate = nullptr);
672
673// These macros expects a `Isolate* isolate` and a `Local<Context> context`
674// to be in the scope.
675#define READONLY_PROPERTY(obj, name, value)do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING
(isolate, name), value, v8::ReadOnly) .Check(); } while (0)
\
676 do { \
677 obj->DefineOwnProperty( \
678 context, FIXED_ONE_BYTE_STRING(isolate, name), value, v8::ReadOnly) \
679 .Check(); \
680 } while (0)
681
682#define READONLY_DONT_ENUM_PROPERTY(obj, name, var)do { obj->DefineOwnProperty( context, OneByteString(isolate
, name), var, static_cast<v8::PropertyAttribute>(v8::ReadOnly
| v8::DontEnum)) .Check(); } while (0)
\
683 do { \
684 obj->DefineOwnProperty( \
685 context, \
686 OneByteString(isolate, name), \
687 var, \
688 static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum)) \
689 .Check(); \
690 } while (0)
691
692#define READONLY_FALSE_PROPERTY(obj, name)do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING
(isolate, name), v8::False(isolate), v8::ReadOnly) .Check(); }
while (0)
\
693 READONLY_PROPERTY(obj, name, v8::False(isolate))do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING
(isolate, name), v8::False(isolate), v8::ReadOnly) .Check(); }
while (0)
694
695#define READONLY_TRUE_PROPERTY(obj, name)do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING
(isolate, name), v8::True(isolate), v8::ReadOnly) .Check(); }
while (0)
\
696 READONLY_PROPERTY(obj, name, v8::True(isolate))do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING
(isolate, name), v8::True(isolate), v8::ReadOnly) .Check(); }
while (0)
697
698#define READONLY_STRING_PROPERTY(obj, name, str)do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING
(isolate, name), ToV8Value(context, str).ToLocalChecked(), v8
::ReadOnly) .Check(); } while (0)
\
699 READONLY_PROPERTY(obj, name, ToV8Value(context, str).ToLocalChecked())do { obj->DefineOwnProperty( context, FIXED_ONE_BYTE_STRING
(isolate, name), ToV8Value(context, str).ToLocalChecked(), v8
::ReadOnly) .Check(); } while (0)
700
701// Variation on NODE_DEFINE_CONSTANT that sets a String value.
702#define NODE_DEFINE_STRING_CONSTANT(target, name, constant)do { v8::Isolate* isolate = target->GetIsolate(); v8::Local
<v8::String> constant_name = v8::String::NewFromUtf8(isolate
, name).ToLocalChecked(); v8::Local<v8::String> constant_value
= v8::String::NewFromUtf8(isolate, constant).ToLocalChecked(
); v8::PropertyAttribute constant_attributes = static_cast<
v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); target
->DefineOwnProperty(isolate->GetCurrentContext(), constant_name
, constant_value, constant_attributes) .Check(); } while (0)
\
703 do { \
704 v8::Isolate* isolate = target->GetIsolate(); \
705 v8::Local<v8::String> constant_name = \
706 v8::String::NewFromUtf8(isolate, name).ToLocalChecked(); \
707 v8::Local<v8::String> constant_value = \
708 v8::String::NewFromUtf8(isolate, constant).ToLocalChecked(); \
709 v8::PropertyAttribute constant_attributes = \
710 static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); \
711 target \
712 ->DefineOwnProperty(isolate->GetCurrentContext(), \
713 constant_name, \
714 constant_value, \
715 constant_attributes) \
716 .Check(); \
717 } while (0)
718
719enum Endianness {
720 kLittleEndian, // _Not_ LITTLE_ENDIAN, clashes with endian.h.
721 kBigEndian
722};
723
724inline enum Endianness GetEndianness() {
725 // Constant-folded by the compiler.
726 const union {
727 uint8_t u8[2];
728 uint16_t u16;
729 } u = {{1, 0}};
730 return u.u16 == 1 ? kLittleEndian : kBigEndian;
731}
732
733inline bool IsLittleEndian() {
734 return GetEndianness() == kLittleEndian;
735}
736
737inline bool IsBigEndian() {
738 return GetEndianness() == kBigEndian;
739}
740
741// Round up a to the next highest multiple of b.
742template <typename T>
743constexpr T RoundUp(T a, T b) {
744 return a % b != 0 ? a + b - (a % b) : a;
745}
746
747// Align ptr to an `alignment`-bytes boundary.
748template <typename T, typename U>
749constexpr T* AlignUp(T* ptr, U alignment) {
750 return reinterpret_cast<T*>(
751 RoundUp(reinterpret_cast<uintptr_t>(ptr), alignment));
752}
753
754class SlicedArguments : public MaybeStackBuffer<v8::Local<v8::Value>> {
755 public:
756 inline explicit SlicedArguments(
757 const v8::FunctionCallbackInfo<v8::Value>& args, size_t start = 0);
758};
759
760// Convert a v8::PersistentBase, e.g. v8::Global, to a Local, with an extra
761// optimization for strong persistent handles.
762class PersistentToLocal {
763 public:
764 // If persistent.IsWeak() == false, then do not call persistent.Reset()
765 // while the returned Local<T> is still in scope, it will destroy the
766 // reference to the object.
767 template <class TypeName>
768 static inline v8::Local<TypeName> Default(
769 v8::Isolate* isolate,
770 const v8::PersistentBase<TypeName>& persistent) {
771 if (persistent.IsWeak()) {
772 return PersistentToLocal::Weak(isolate, persistent);
773 } else {
774 return PersistentToLocal::Strong(persistent);
775 }
776 }
777
778 // Unchecked conversion from a non-weak Persistent<T> to Local<T>,
779 // use with care!
780 //
781 // Do not call persistent.Reset() while the returned Local<T> is still in
782 // scope, it will destroy the reference to the object.
783 template <class TypeName>
784 static inline v8::Local<TypeName> Strong(
785 const v8::PersistentBase<TypeName>& persistent) {
786 DCHECK(!persistent.IsWeak());
787 return *reinterpret_cast<v8::Local<TypeName>*>(
788 const_cast<v8::PersistentBase<TypeName>*>(&persistent));
789 }
790
791 template <class TypeName>
792 static inline v8::Local<TypeName> Weak(
793 v8::Isolate* isolate,
794 const v8::PersistentBase<TypeName>& persistent) {
795 return v8::Local<TypeName>::New(isolate, persistent);
796 }
797};
798
799// Can be used as a key for std::unordered_map when lookup performance is more
800// important than size and the keys are statically used to avoid redundant hash
801// computations.
802class FastStringKey {
803 public:
804 constexpr explicit FastStringKey(const char* name);
805
806 struct Hash {
807 constexpr size_t operator()(const FastStringKey& key) const;
808 };
809 constexpr bool operator==(const FastStringKey& other) const;
810
811 constexpr const char* c_str() const;
812
813 private:
814 static constexpr size_t HashImpl(const char* str);
815
816 const char* name_;
817 size_t cached_hash_;
818};
819
820// Like std::static_pointer_cast but for unique_ptr with the default deleter.
821template <typename T, typename U>
822std::unique_ptr<T> static_unique_pointer_cast(std::unique_ptr<U>&& ptr) {
823 return std::unique_ptr<T>(static_cast<T*>(ptr.release()));
824}
825
826#define MAYBE_FIELD_PTR(ptr, field)ptr == nullptr ? nullptr : &(ptr->field) ptr == nullptr ? nullptr : &(ptr->field)
827
828// Returns a non-zero code if it fails to open or read the file,
829// aborts if it fails to close the file.
830int ReadFileSync(std::string* result, const char* path);
831} // namespace node
832
833#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
834
835#endif // SRC_UTIL_H_

../src/crypto/crypto_keys.h

1#ifndef SRC_CRYPTO_CRYPTO_KEYS_H_
2#define SRC_CRYPTO_CRYPTO_KEYS_H_
3
4#if defined(NODE_WANT_INTERNALS1) && NODE_WANT_INTERNALS1
5
6#include "crypto/crypto_util.h"
7#include "base_object.h"
8#include "env.h"
9#include "memory_tracker.h"
10#include "node_buffer.h"
11#include "node_worker.h"
12#include "v8.h"
13
14#include <openssl/evp.h>
15
16#include <memory>
17#include <string>
18
19namespace node {
20namespace crypto {
21enum PKEncodingType {
22 // RSAPublicKey / RSAPrivateKey according to PKCS#1.
23 kKeyEncodingPKCS1,
24 // PrivateKeyInfo or EncryptedPrivateKeyInfo according to PKCS#8.
25 kKeyEncodingPKCS8,
26 // SubjectPublicKeyInfo according to X.509.
27 kKeyEncodingSPKI,
28 // ECPrivateKey according to SEC1.
29 kKeyEncodingSEC1
30};
31
32enum PKFormatType {
33 kKeyFormatDER,
34 kKeyFormatPEM,
35 kKeyFormatJWK
36};
37
38enum KeyType {
39 kKeyTypeSecret,
40 kKeyTypePublic,
41 kKeyTypePrivate
42};
43
44enum KeyEncodingContext {
45 kKeyContextInput,
46 kKeyContextExport,
47 kKeyContextGenerate
48};
49
50enum class ParseKeyResult {
51 kParseKeyOk,
52 kParseKeyNotRecognized,
53 kParseKeyNeedPassphrase,
54 kParseKeyFailed
55};
56
57struct AsymmetricKeyEncodingConfig {
58 bool output_key_object_ = false;
59 PKFormatType format_ = kKeyFormatDER;
60 v8::Maybe<PKEncodingType> type_ = v8::Nothing<PKEncodingType>();
61};
62
63using PublicKeyEncodingConfig = AsymmetricKeyEncodingConfig;
64
65struct PrivateKeyEncodingConfig : public AsymmetricKeyEncodingConfig {
22
Value assigned to field 'cipher_' in implicit constructor is garbage or undefined
66 const EVP_CIPHER* cipher_;
67 // The ByteSource alone is not enough to distinguish between "no passphrase"
68 // and a zero-length passphrase (which can be a null pointer), therefore, we
69 // use a NonCopyableMaybe.
70 NonCopyableMaybe<ByteSource> passphrase_;
71};
72
73// This uses the built-in reference counter of OpenSSL to manage an EVP_PKEY
74// which is slightly more efficient than using a shared pointer and easier to
75// use.
76class ManagedEVPPKey : public MemoryRetainer {
77 public:
78 ManagedEVPPKey() : mutex_(std::make_shared<Mutex>()) {}
79 explicit ManagedEVPPKey(EVPKeyPointer&& pkey);
80 ManagedEVPPKey(const ManagedEVPPKey& that);
81 ManagedEVPPKey& operator=(const ManagedEVPPKey& that);
82
83 operator bool() const;
84 EVP_PKEY* get() const;
85 Mutex* mutex() const;
86
87 void MemoryInfo(MemoryTracker* tracker) const override;
88 SET_MEMORY_INFO_NAME(ManagedEVPPKey)inline std::string MemoryInfoName() const override { return "ManagedEVPPKey"
; }
89 SET_SELF_SIZE(ManagedEVPPKey)inline size_t SelfSize() const override { return sizeof(ManagedEVPPKey
); }
90
91 static PublicKeyEncodingConfig GetPublicKeyEncodingFromJs(
92 const v8::FunctionCallbackInfo<v8::Value>& args,
93 unsigned int* offset,
94 KeyEncodingContext context);
95
96 static NonCopyableMaybe<PrivateKeyEncodingConfig> GetPrivateKeyEncodingFromJs(
97 const v8::FunctionCallbackInfo<v8::Value>& args,
98 unsigned int* offset,
99 KeyEncodingContext context);
100
101 static ManagedEVPPKey GetParsedKey(Environment* env,
102 EVPKeyPointer&& pkey,
103 ParseKeyResult ret,
104 const char* default_msg);
105
106 static ManagedEVPPKey GetPublicOrPrivateKeyFromJs(
107 const v8::FunctionCallbackInfo<v8::Value>& args,
108 unsigned int* offset);
109
110 static ManagedEVPPKey GetPrivateKeyFromJs(
111 const v8::FunctionCallbackInfo<v8::Value>& args,
112 unsigned int* offset,
113 bool allow_key_object);
114
115 static v8::Maybe<bool> ToEncodedPublicKey(
116 Environment* env,
117 ManagedEVPPKey key,
118 const PublicKeyEncodingConfig& config,
119 v8::Local<v8::Value>* out);
120
121 static v8::Maybe<bool> ToEncodedPrivateKey(
122 Environment* env,
123 ManagedEVPPKey key,
124 const PrivateKeyEncodingConfig& config,
125 v8::Local<v8::Value>* out);
126
127 private:
128 size_t size_of_private_key() const;
129 size_t size_of_public_key() const;
130
131 EVPKeyPointer pkey_;
132 std::shared_ptr<Mutex> mutex_;
133};
134
135// Objects of this class can safely be shared among threads.
136class KeyObjectData : public MemoryRetainer {
137 public:
138 static std::shared_ptr<KeyObjectData> CreateSecret(ByteSource key);
139
140 static std::shared_ptr<KeyObjectData> CreateAsymmetric(
141 KeyType type,
142 const ManagedEVPPKey& pkey);
143
144 KeyType GetKeyType() const;
145
146 // These functions allow unprotected access to the raw key material and should
147 // only be used to implement cryptographic operations requiring the key.
148 ManagedEVPPKey GetAsymmetricKey() const;
149 const char* GetSymmetricKey() const;
150 size_t GetSymmetricKeySize() const;
151
152 void MemoryInfo(MemoryTracker* tracker) const override;
153 SET_MEMORY_INFO_NAME(KeyObjectData)inline std::string MemoryInfoName() const override { return "KeyObjectData"
; }
154 SET_SELF_SIZE(KeyObjectData)inline size_t SelfSize() const override { return sizeof(KeyObjectData
); }
155
156 private:
157 explicit KeyObjectData(ByteSource symmetric_key);
158
159 KeyObjectData(
160 KeyType type,
161 const ManagedEVPPKey& pkey);
162
163 const KeyType key_type_;
164 const ByteSource symmetric_key_;
165 const unsigned int symmetric_key_len_;
166 const ManagedEVPPKey asymmetric_key_;
167};
168
169class KeyObjectHandle : public BaseObject {
170 public:
171 static v8::Local<v8::Function> Initialize(Environment* env);
172 static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
173
174 static v8::MaybeLocal<v8::Object> Create(Environment* env,
175 std::shared_ptr<KeyObjectData> data);
176
177 // TODO(tniessen): track the memory used by OpenSSL types
178 SET_NO_MEMORY_INFO()inline void MemoryInfo(node::MemoryTracker* tracker) const override
{}
179 SET_MEMORY_INFO_NAME(KeyObjectHandle)inline std::string MemoryInfoName() const override { return "KeyObjectHandle"
; }
180 SET_SELF_SIZE(KeyObjectHandle)inline size_t SelfSize() const override { return sizeof(KeyObjectHandle
); }
181
182 const std::shared_ptr<KeyObjectData>& Data();
183
184 protected:
185 static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
186
187 static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
188 static void InitECRaw(const v8::FunctionCallbackInfo<v8::Value>& args);
189 static void InitEDRaw(const v8::FunctionCallbackInfo<v8::Value>& args);
190 static void InitJWK(const v8::FunctionCallbackInfo<v8::Value>& args);
191 static void GetKeyDetail(const v8::FunctionCallbackInfo<v8::Value>& args);
192 static void Equals(const v8::FunctionCallbackInfo<v8::Value>& args);
193
194 static void ExportJWK(const v8::FunctionCallbackInfo<v8::Value>& args);
195
196 static void GetAsymmetricKeyType(
197 const v8::FunctionCallbackInfo<v8::Value>& args);
198 v8::Local<v8::Value> GetAsymmetricKeyType() const;
199
200 static void GetSymmetricKeySize(
201 const v8::FunctionCallbackInfo<v8::Value>& args);
202
203 static void Export(const v8::FunctionCallbackInfo<v8::Value>& args);
204
205 v8::MaybeLocal<v8::Value> ExportSecretKey() const;
206 v8::MaybeLocal<v8::Value> ExportPublicKey(
207 const PublicKeyEncodingConfig& config) const;
208 v8::MaybeLocal<v8::Value> ExportPrivateKey(
209 const PrivateKeyEncodingConfig& config) const;
210
211 KeyObjectHandle(Environment* env,
212 v8::Local<v8::Object> wrap);
213
214 private:
215 std::shared_ptr<KeyObjectData> data_;
216};
217
218class NativeKeyObject : public BaseObject {
219 public:
220 static void Initialize(Environment* env, v8::Local<v8::Object> target);
221 static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
222
223 static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
224 static void CreateNativeKeyObjectClass(
225 const v8::FunctionCallbackInfo<v8::Value>& args);
226
227 SET_NO_MEMORY_INFO()inline void MemoryInfo(node::MemoryTracker* tracker) const override
{}
228 SET_MEMORY_INFO_NAME(NativeKeyObject)inline std::string MemoryInfoName() const override { return "NativeKeyObject"
; }
229 SET_SELF_SIZE(NativeKeyObject)inline size_t SelfSize() const override { return sizeof(NativeKeyObject
); }
230
231 class KeyObjectTransferData : public worker::TransferData {
232 public:
233 explicit KeyObjectTransferData(const std::shared_ptr<KeyObjectData>& data)
234 : data_(data) {}
235
236 BaseObjectPtr<BaseObject> Deserialize(
237 Environment* env,
238 v8::Local<v8::Context> context,
239 std::unique_ptr<worker::TransferData> self) override;
240
241 SET_MEMORY_INFO_NAME(KeyObjectTransferData)inline std::string MemoryInfoName() const override { return "KeyObjectTransferData"
; }
242 SET_SELF_SIZE(KeyObjectTransferData)inline size_t SelfSize() const override { return sizeof(KeyObjectTransferData
); }
243 SET_NO_MEMORY_INFO()inline void MemoryInfo(node::MemoryTracker* tracker) const override
{}
244
245 private:
246 std::shared_ptr<KeyObjectData> data_;
247 };
248
249 BaseObject::TransferMode GetTransferMode() const override;
250 std::unique_ptr<worker::TransferData> CloneForMessaging() const override;
251
252 private:
253 NativeKeyObject(Environment* env,
254 v8::Local<v8::Object> wrap,
255 const std::shared_ptr<KeyObjectData>& handle_data)
256 : BaseObject(env, wrap),
257 handle_data_(handle_data) {
258 MakeWeak();
259 }
260
261 std::shared_ptr<KeyObjectData> handle_data_;
262};
263
264enum WebCryptoKeyFormat {
265 kWebCryptoKeyFormatRaw,
266 kWebCryptoKeyFormatPKCS8,
267 kWebCryptoKeyFormatSPKI,
268 kWebCryptoKeyFormatJWK
269};
270
271enum class WebCryptoKeyExportStatus {
272 OK,
273 INVALID_KEY_TYPE,
274 FAILED
275};
276
277template <typename KeyExportTraits>
278class KeyExportJob final : public CryptoJob<KeyExportTraits> {
279 public:
280 using AdditionalParams = typename KeyExportTraits::AdditionalParameters;
281
282 static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
283 Environment* env = Environment::GetCurrent(args);
284 CHECK(args.IsConstructCall())do { if (__builtin_expect(!!(!(args.IsConstructCall())), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h"
":" "284", "args.IsConstructCall()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
285
286 CryptoJobMode mode = GetCryptoJobMode(args[0]);
287
288 CHECK(args[1]->IsUint32())do { if (__builtin_expect(!!(!(args[1]->IsUint32())), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h"
":" "288", "args[1]->IsUint32()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
; // Export Type
289 CHECK(args[2]->IsObject())do { if (__builtin_expect(!!(!(args[2]->IsObject())), 0)) {
do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h"
":" "289", "args[2]->IsObject()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
; // KeyObject
290
291 WebCryptoKeyFormat format =
292 static_cast<WebCryptoKeyFormat>(args[1].As<v8::Uint32>()->Value());
293
294 KeyObjectHandle* key;
295 ASSIGN_OR_RETURN_UNWRAP(&key, args[2])do { *&key = static_cast<typename std::remove_reference
<decltype(*&key)>::type>( BaseObject::FromJSObject
(args[2])); if (*&key == nullptr) return ; } while (0)
;
296
297 CHECK_NOT_NULL(key)do { if (__builtin_expect(!!(!((key) != nullptr)), 0)) { do {
static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h"
":" "297", "(key) != nullptr", __PRETTY_FUNCTION__ }; node::
Assert(args); } while (0); } } while (0)
;
298
299 AdditionalParams params;
300 if (KeyExportTraits::AdditionalConfig(args, 3, &params).IsNothing()) {
301 // The KeyExportTraits::AdditionalConfig is responsible for
302 // calling an appropriate THROW_CRYPTO_* variant reporting
303 // whatever error caused initialization to fail.
304 return;
305 }
306
307 new KeyExportJob<KeyExportTraits>(
308 env,
309 args.This(),
310 mode,
311 key->Data(),
312 format,
313 std::move(params));
314 }
315
316 static void Initialize(
317 Environment* env,
318 v8::Local<v8::Object> target) {
319 CryptoJob<KeyExportTraits>::Initialize(New, env, target);
320 }
321
322 static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
323 CryptoJob<KeyExportTraits>::RegisterExternalReferences(New, registry);
324 }
325
326 KeyExportJob(
327 Environment* env,
328 v8::Local<v8::Object> object,
329 CryptoJobMode mode,
330 std::shared_ptr<KeyObjectData> key,
331 WebCryptoKeyFormat format,
332 AdditionalParams&& params)
333 : CryptoJob<KeyExportTraits>(
334 env,
335 object,
336 AsyncWrap::PROVIDER_KEYEXPORTREQUEST,
337 mode,
338 std::move(params)),
339 key_(key),
340 format_(format) {}
341
342 WebCryptoKeyFormat format() const { return format_; }
343
344 void DoThreadPoolWork() override {
345 const WebCryptoKeyExportStatus status =
346 KeyExportTraits::DoExport(
347 key_,
348 format_,
349 *CryptoJob<KeyExportTraits>::params(),
350 &out_);
351 if (status == WebCryptoKeyExportStatus::OK) {
352 // Success!
353 return;
354 }
355 CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors();
356 errors->Capture();
357 if (errors->Empty()) {
358 switch (status) {
359 case WebCryptoKeyExportStatus::OK:
360 UNREACHABLE()do { static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h"
":" "360", "\"Unreachable code reached\"", __PRETTY_FUNCTION__
}; node::Assert(args); } while (0)
;
361 break;
362 case WebCryptoKeyExportStatus::INVALID_KEY_TYPE:
363 errors->Insert(NodeCryptoError::INVALID_KEY_TYPE);
364 break;
365 case WebCryptoKeyExportStatus::FAILED:
366 errors->Insert(NodeCryptoError::CIPHER_JOB_FAILED);
367 break;
368 }
369 }
370 }
371
372 v8::Maybe<bool> ToResult(
373 v8::Local<v8::Value>* err,
374 v8::Local<v8::Value>* result) override {
375 Environment* env = AsyncWrap::env();
376 CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors();
377 if (out_.size() > 0) {
378 CHECK(errors->Empty())do { if (__builtin_expect(!!(!(errors->Empty())), 0)) { do
{ static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h"
":" "378", "errors->Empty()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
379 *err = v8::Undefined(env->isolate());
380 *result = out_.ToArrayBuffer(env);
381 return v8::Just(!result->IsEmpty());
382 }
383
384 if (errors->Empty())
385 errors->Capture();
386 CHECK(!errors->Empty())do { if (__builtin_expect(!!(!(!errors->Empty())), 0)) { do
{ static const node::AssertionInfo args = { "../src/crypto/crypto_keys.h"
":" "386", "!errors->Empty()", __PRETTY_FUNCTION__ }; node
::Assert(args); } while (0); } } while (0)
;
387 *result = v8::Undefined(env->isolate());
388 return v8::Just(errors->ToException(env).ToLocal(err));
389 }
390
391 SET_SELF_SIZE(KeyExportJob)inline size_t SelfSize() const override { return sizeof(KeyExportJob
); }
392 void MemoryInfo(MemoryTracker* tracker) const override {
393 tracker->TrackFieldWithSize("out", out_.size());
394 CryptoJob<KeyExportTraits>::MemoryInfo(tracker);
395 }
396
397 private:
398 std::shared_ptr<KeyObjectData> key_;
399 WebCryptoKeyFormat format_;
400 ByteSource out_;
401};
402
403WebCryptoKeyExportStatus PKEY_SPKI_Export(
404 KeyObjectData* key_data,
405 ByteSource* out);
406
407WebCryptoKeyExportStatus PKEY_PKCS8_Export(
408 KeyObjectData* key_data,
409 ByteSource* out);
410
411namespace Keys {
412void Initialize(Environment* env, v8::Local<v8::Object> target);
413void RegisterExternalReferences(ExternalReferenceRegistry* registry);
414} // namespace Keys
415
416} // namespace crypto
417} // namespace node
418
419#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
420#endif // SRC_CRYPTO_CRYPTO_KEYS_H_