File: | out/../src/crypto/crypto_keys.h |
Warning: | line 65, column 8 Value assigned to field 'cipher_' in implicit constructor is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |||||||
19 | namespace node { | ||||||
20 | |||||||
21 | using v8::Array; | ||||||
22 | using v8::Context; | ||||||
23 | using v8::Function; | ||||||
24 | using v8::FunctionCallbackInfo; | ||||||
25 | using v8::FunctionTemplate; | ||||||
26 | using v8::Int32; | ||||||
27 | using v8::Just; | ||||||
28 | using v8::Local; | ||||||
29 | using v8::Maybe; | ||||||
30 | using v8::MaybeLocal; | ||||||
31 | using v8::NewStringType; | ||||||
32 | using v8::Nothing; | ||||||
33 | using v8::Number; | ||||||
34 | using v8::Object; | ||||||
35 | using v8::String; | ||||||
36 | using v8::Uint32; | ||||||
37 | using v8::Undefined; | ||||||
38 | using v8::Value; | ||||||
39 | |||||||
40 | namespace crypto { | ||||||
41 | namespace { | ||||||
42 | void 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 | |||||||
77 | ParseKeyResult 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 | |||||||
103 | ParseKeyResult 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 | |||||||
138 | ParseKeyResult 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 | |||||||
160 | bool 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 | |||||||
184 | bool 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 | |||||||
201 | bool 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 | |||||||
213 | ParseKeyResult 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 | |||||||
272 | MaybeLocal<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 | |||||||
292 | MaybeLocal<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 | |||||||
392 | bool 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 | |||||||
420 | MaybeLocal<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 | |||||||
433 | Maybe<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 | |||||||
470 | std::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 | |||||||
489 | Maybe<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 | |||||||
514 | std::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 | |||||||
530 | Maybe<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 | |||||||
543 | Maybe<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 | |||||||
560 | ManagedEVPPKey::ManagedEVPPKey(EVPKeyPointer&& pkey) : pkey_(std::move(pkey)), | ||||||
561 | mutex_(std::make_shared<Mutex>()) {} | ||||||
562 | |||||||
563 | ManagedEVPPKey::ManagedEVPPKey(const ManagedEVPPKey& that) { | ||||||
564 | *this = that; | ||||||
565 | } | ||||||
566 | |||||||
567 | ManagedEVPPKey& 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 | |||||||
580 | ManagedEVPPKey::operator bool() const { | ||||||
581 | return !!pkey_; | ||||||
582 | } | ||||||
583 | |||||||
584 | EVP_PKEY* ManagedEVPPKey::get() const { | ||||||
585 | return pkey_.get(); | ||||||
586 | } | ||||||
587 | |||||||
588 | Mutex* ManagedEVPPKey::mutex() const { | ||||||
589 | return mutex_.get(); | ||||||
590 | } | ||||||
591 | |||||||
592 | void 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 | |||||||
599 | size_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 | |||||||
605 | size_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>(). | ||||||
612 | static inline Maybe<bool> Tristate(bool b) { | ||||||
613 | return b ? Just(true) : Nothing<bool>(); | ||||||
614 | } | ||||||
615 | |||||||
616 | Maybe<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 | |||||||
633 | Maybe<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 | |||||||
655 | Maybe<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 | |||||||
675 | NonCopyableMaybe<PrivateKeyEncodingConfig> | ||||||
676 | ManagedEVPPKey::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_
| ||||||
686 | if (context != kKeyContextInput) | ||||||
687 | (*offset)++; | ||||||
688 | } else { | ||||||
689 | bool needs_passphrase = false; | ||||||
690 | if (context
| ||||||
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])) { | ||||||
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); | ||||||
717 | } | ||||||
718 | } | ||||||
719 | |||||||
720 | (*offset)++; | ||||||
721 | return NonCopyableMaybe<PrivateKeyEncodingConfig>(std::move(result)); | ||||||
722 | } | ||||||
723 | |||||||
724 | PublicKeyEncodingConfig 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 | |||||||
733 | ManagedEVPPKey ManagedEVPPKey::GetPrivateKeyFromJs( | ||||||
734 | const FunctionCallbackInfo<Value>& args, | ||||||
735 | unsigned int* offset, | ||||||
736 | bool allow_key_object) { | ||||||
737 | if (args[*offset]->IsString() || IsAnyByteSource(args[*offset])) { | ||||||
738 | Environment* env = Environment::GetCurrent(args); | ||||||
739 | ByteSource key = ByteSource::FromStringOrBuffer(env, args[(*offset)++]); | ||||||
740 | NonCopyableMaybe<PrivateKeyEncodingConfig> config = | ||||||
741 | GetPrivateKeyEncodingFromJs(args, offset, kKeyContextInput); | ||||||
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 | |||||||
760 | ManagedEVPPKey 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 | |||||||
824 | ManagedEVPPKey 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 | |||||||
843 | KeyObjectData::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 | |||||||
850 | KeyObjectData::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 | |||||||
858 | void 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 | |||||||
873 | std::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 | |||||||
878 | std::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 | |||||||
885 | KeyType KeyObjectData::GetKeyType() const { | ||||||
886 | return key_type_; | ||||||
887 | } | ||||||
888 | |||||||
889 | ManagedEVPPKey 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 | |||||||
894 | const 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 | |||||||
899 | size_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 | |||||||
904 | v8::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 | |||||||
932 | void 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 | |||||||
947 | MaybeLocal<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 | |||||||
962 | const std::shared_ptr<KeyObjectData>& KeyObjectHandle::Data() { | ||||||
963 | return data_; | ||||||
964 | } | ||||||
965 | |||||||
966 | void 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 | |||||||
972 | KeyObjectHandle::KeyObjectHandle(Environment* env, | ||||||
973 | Local<Object> wrap) | ||||||
974 | : BaseObject(env, wrap) { | ||||||
975 | MakeWeak(); | ||||||
976 | } | ||||||
977 | |||||||
978 | void 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); | ||||||
| |||||||
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); | ||||||
984 | KeyType type = static_cast<KeyType>(args[0].As<Uint32>()->Value()); | ||||||
985 | |||||||
986 | unsigned int offset; | ||||||
987 | ManagedEVPPKey pkey; | ||||||
988 | |||||||
989 | switch (type) { | ||||||
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); | ||||||
1008 | |||||||
1009 | offset = 1; | ||||||
1010 | pkey = ManagedEVPPKey::GetPrivateKeyFromJs(args, &offset, false); | ||||||
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 | |||||||
1021 | void 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 | |||||||
1060 | void 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 | |||||||
1098 | void 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 | |||||||
1140 | void 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 | |||||||
1188 | void 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 | |||||||
1215 | Local<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 | |||||||
1241 | void 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 | |||||||
1249 | void 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 | |||||||
1257 | void 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 | |||||||
1289 | MaybeLocal<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 | |||||||
1295 | MaybeLocal<Value> KeyObjectHandle::ExportPublicKey( | ||||||
1296 | const PublicKeyEncodingConfig& config) const { | ||||||
1297 | return WritePublicKey(env(), data_->GetAsymmetricKey().get(), config); | ||||||
1298 | } | ||||||
1299 | |||||||
1300 | MaybeLocal<Value> KeyObjectHandle::ExportPrivateKey( | ||||||
1301 | const PrivateKeyEncodingConfig& config) const { | ||||||
1302 | return WritePrivateKey(env(), data_->GetAsymmetricKey().get(), config); | ||||||
1303 | } | ||||||
1304 | |||||||
1305 | void 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 | |||||||
1319 | void NativeKeyObject::Initialize(Environment* env, Local<Object> target) { | ||||||
1320 | env->SetMethod(target, "createNativeKeyObjectClass", | ||||||
1321 | NativeKeyObject::CreateNativeKeyObjectClass); | ||||||
1322 | } | ||||||
1323 | |||||||
1324 | void NativeKeyObject::RegisterExternalReferences( | ||||||
1325 | ExternalReferenceRegistry* registry) { | ||||||
1326 | registry->Register(NativeKeyObject::CreateNativeKeyObjectClass); | ||||||
1327 | registry->Register(NativeKeyObject::New); | ||||||
1328 | } | ||||||
1329 | |||||||
1330 | void 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 | |||||||
1338 | void 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 | |||||||
1371 | BaseObjectPtr<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 | |||||||
1412 | BaseObject::TransferMode NativeKeyObject::GetTransferMode() const { | ||||||
1413 | return BaseObject::TransferMode::kCloneable; | ||||||
1414 | } | ||||||
1415 | |||||||
1416 | std::unique_ptr<worker::TransferData> NativeKeyObject::CloneForMessaging() | ||||||
1417 | const { | ||||||
1418 | return std::make_unique<KeyObjectTransferData>(handle_data_); | ||||||
1419 | } | ||||||
1420 | |||||||
1421 | WebCryptoKeyExportStatus 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 | |||||||
1436 | WebCryptoKeyExportStatus 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 | |||||||
1453 | namespace Keys { | ||||||
1454 | void 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 | |||||||
1482 | void RegisterExternalReferences(ExternalReferenceRegistry* registry) { | ||||||
1483 | KeyObjectHandle::RegisterExternalReferences(registry); | ||||||
1484 | } | ||||||
1485 | } // namespace Keys | ||||||
1486 | |||||||
1487 | } // namespace crypto | ||||||
1488 | } // namespace node |
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 | |
54 | namespace 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. |
73 | template <typename T> |
74 | inline T* UncheckedRealloc(T* pointer, size_t n); |
75 | template <typename T> |
76 | inline T* UncheckedMalloc(size_t n); |
77 | template <typename T> |
78 | inline T* UncheckedCalloc(size_t n); |
79 | |
80 | // Same things, but aborts immediately instead of returning nullptr when |
81 | // no memory is available. |
82 | template <typename T> |
83 | inline T* Realloc(T* pointer, size_t n); |
84 | template <typename T> |
85 | inline T* Malloc(size_t n); |
86 | template <typename T> |
87 | inline T* Calloc(size_t n); |
88 | |
89 | inline char* Malloc(size_t n); |
90 | inline char* Calloc(size_t n); |
91 | inline char* UncheckedMalloc(size_t n); |
92 | inline char* UncheckedCalloc(size_t n); |
93 | |
94 | template <typename T> |
95 | inline T MultiplyWithOverflowCheck(T a, T b); |
96 | |
97 | namespace per_process { |
98 | // Tells whether the per-process V8::Initialize() is called and |
99 | // if it is safe to call v8::Isolate::TryGetCurrent(). |
100 | extern 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. |
106 | void 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. |
110 | struct 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(); |
117 | void 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) |
197 | constexpr int64_t kMaxSafeJsInteger = 9007199254740991; |
198 | |
199 | inline bool IsSafeJsInt(v8::Local<v8::Value> v); |
200 | |
201 | // TAILQ-style intrusive list node. |
202 | template <typename T> |
203 | class ListNode; |
204 | |
205 | // TAILQ-style intrusive list head. |
206 | template <typename T, ListNode<T> (T::*M)> |
207 | class ListHead; |
208 | |
209 | template <typename T> |
210 | class 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 | |
227 | template <typename T, ListNode<T> (T::*M)> |
228 | class 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. |
260 | template <typename Inner, typename Outer> |
261 | class 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. |
272 | template <typename Inner, typename Outer> |
273 | constexpr ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field, |
274 | Inner* pointer); |
275 | |
276 | // Convenience wrapper around v8::String::NewFromOneByte(). |
277 | inline 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. |
282 | inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate, |
283 | const signed char* data, |
284 | int length = -1); |
285 | |
286 | inline 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. |
291 | template <int N> |
292 | inline 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 | |
298 | template <std::size_t N> |
299 | inline 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). |
309 | inline void SwapBytes16(char* data, size_t nbytes); |
310 | inline void SwapBytes32(char* data, size_t nbytes); |
311 | inline void SwapBytes64(char* data, size_t nbytes); |
312 | |
313 | // tolower() is locale-sensitive. Use ToLower() instead. |
314 | inline char ToLower(char c); |
315 | inline std::string ToLower(const std::string& in); |
316 | |
317 | // toupper() is locale-sensitive. Use ToUpper() instead. |
318 | inline char ToUpper(char c); |
319 | inline std::string ToUpper(const std::string& in); |
320 | |
321 | // strcasecmp() is locale-sensitive. Use StringEqualNoCase() instead. |
322 | inline bool StringEqualNoCase(const char* a, const char* b); |
323 | |
324 | // strncasecmp() is locale-sensitive. Use StringEqualNoCaseN() instead. |
325 | inline bool StringEqualNoCaseN(const char* a, const char* b, size_t length); |
326 | |
327 | template <typename T, size_t N> |
328 | constexpr size_t arraysize(const T (&)[N]) { |
329 | return N; |
330 | } |
331 | |
332 | template <typename T, size_t N> |
333 | constexpr 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(). |
339 | template <typename T, size_t kStackStorageSize = 1024> |
340 | class 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. |
468 | template <typename T, size_t kStackStorageSize = 64> |
469 | class 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 | |
487 | class 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 | |
498 | class TwoByteValue : public MaybeStackBuffer<uint16_t> { |
499 | public: |
500 | explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value); |
501 | }; |
502 | |
503 | class 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. |
524 | template <typename T> inline void USE(T&&) {} |
525 | |
526 | template <typename Fn> |
527 | struct 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 | // }); |
552 | template <typename Fn> |
553 | inline 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(). |
558 | template <typename T> |
559 | struct 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 | |
598 | template <typename T> |
599 | class NonCopyableMaybe { |
600 | public: |
601 | NonCopyableMaybe() : empty_(true) {} |
602 | explicit NonCopyableMaybe(T&& value) |
603 | : empty_(false), |
604 | value_(std::move(value)) {} |
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 (). |
631 | template <typename T, typename = void> |
632 | struct is_callable : std::is_function<T> { }; |
633 | |
634 | template <typename T> |
635 | struct is_callable<T, typename std::enable_if< |
636 | std::is_same<decltype(void(&T::operator())), void>::value |
637 | >::type> : std::true_type { }; |
638 | |
639 | template <typename T, void (*function)(T*)> |
640 | struct FunctionDeleter { |
641 | void operator()(T* pointer) const { function(pointer); } |
642 | typedef std::unique_ptr<T, FunctionDeleter> Pointer; |
643 | }; |
644 | |
645 | template <typename T, void (*function)(T*)> |
646 | using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer; |
647 | |
648 | std::vector<std::string> SplitString(const std::string& in, |
649 | char delim, |
650 | bool skipEmpty = true); |
651 | |
652 | inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
653 | std::string_view str, |
654 | v8::Isolate* isolate = nullptr); |
655 | template <typename T, typename test_for_number = |
656 | typename std::enable_if<std::numeric_limits<T>::is_specialized, bool>::type> |
657 | inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
658 | const T& number, |
659 | v8::Isolate* isolate = nullptr); |
660 | template <typename T> |
661 | inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
662 | const std::vector<T>& vec, |
663 | v8::Isolate* isolate = nullptr); |
664 | template <typename T> |
665 | inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
666 | const std::set<T>& set, |
667 | v8::Isolate* isolate = nullptr); |
668 | template <typename T, typename U> |
669 | inline 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 | |
719 | enum Endianness { |
720 | kLittleEndian, // _Not_ LITTLE_ENDIAN, clashes with endian.h. |
721 | kBigEndian |
722 | }; |
723 | |
724 | inline 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 | |
733 | inline bool IsLittleEndian() { |
734 | return GetEndianness() == kLittleEndian; |
735 | } |
736 | |
737 | inline bool IsBigEndian() { |
738 | return GetEndianness() == kBigEndian; |
739 | } |
740 | |
741 | // Round up a to the next highest multiple of b. |
742 | template <typename T> |
743 | constexpr 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. |
748 | template <typename T, typename U> |
749 | constexpr T* AlignUp(T* ptr, U alignment) { |
750 | return reinterpret_cast<T*>( |
751 | RoundUp(reinterpret_cast<uintptr_t>(ptr), alignment)); |
752 | } |
753 | |
754 | class 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. |
762 | class 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. |
802 | class 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. |
821 | template <typename T, typename U> |
822 | std::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. |
830 | int 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_ |
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 | ||||
19 | namespace node { | |||
20 | namespace crypto { | |||
21 | enum 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 | ||||
32 | enum PKFormatType { | |||
33 | kKeyFormatDER, | |||
34 | kKeyFormatPEM, | |||
35 | kKeyFormatJWK | |||
36 | }; | |||
37 | ||||
38 | enum KeyType { | |||
39 | kKeyTypeSecret, | |||
40 | kKeyTypePublic, | |||
41 | kKeyTypePrivate | |||
42 | }; | |||
43 | ||||
44 | enum KeyEncodingContext { | |||
45 | kKeyContextInput, | |||
46 | kKeyContextExport, | |||
47 | kKeyContextGenerate | |||
48 | }; | |||
49 | ||||
50 | enum class ParseKeyResult { | |||
51 | kParseKeyOk, | |||
52 | kParseKeyNotRecognized, | |||
53 | kParseKeyNeedPassphrase, | |||
54 | kParseKeyFailed | |||
55 | }; | |||
56 | ||||
57 | struct AsymmetricKeyEncodingConfig { | |||
58 | bool output_key_object_ = false; | |||
59 | PKFormatType format_ = kKeyFormatDER; | |||
60 | v8::Maybe<PKEncodingType> type_ = v8::Nothing<PKEncodingType>(); | |||
61 | }; | |||
62 | ||||
63 | using PublicKeyEncodingConfig = AsymmetricKeyEncodingConfig; | |||
64 | ||||
65 | struct PrivateKeyEncodingConfig : public AsymmetricKeyEncodingConfig { | |||
| ||||
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. | |||
76 | class 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. | |||
136 | class 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 | ||||
169 | class 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 | ||||
218 | class 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 | ||||
264 | enum WebCryptoKeyFormat { | |||
265 | kWebCryptoKeyFormatRaw, | |||
266 | kWebCryptoKeyFormatPKCS8, | |||
267 | kWebCryptoKeyFormatSPKI, | |||
268 | kWebCryptoKeyFormatJWK | |||
269 | }; | |||
270 | ||||
271 | enum class WebCryptoKeyExportStatus { | |||
272 | OK, | |||
273 | INVALID_KEY_TYPE, | |||
274 | FAILED | |||
275 | }; | |||
276 | ||||
277 | template <typename KeyExportTraits> | |||
278 | class 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, ¶ms).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 | ||||
403 | WebCryptoKeyExportStatus PKEY_SPKI_Export( | |||
404 | KeyObjectData* key_data, | |||
405 | ByteSource* out); | |||
406 | ||||
407 | WebCryptoKeyExportStatus PKEY_PKCS8_Export( | |||
408 | KeyObjectData* key_data, | |||
409 | ByteSource* out); | |||
410 | ||||
411 | namespace Keys { | |||
412 | void Initialize(Environment* env, v8::Local<v8::Object> target); | |||
413 | void 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_ |