GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
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 |
#include "node_crypto.h" |
||
23 |
#include "node_buffer.h" |
||
24 |
#include "node_crypto_bio.h" |
||
25 |
#include "node_crypto_clienthello-inl.h" |
||
26 |
#include "node_crypto_groups.h" |
||
27 |
#include "node_errors.h" |
||
28 |
#include "node_mutex.h" |
||
29 |
#include "node_process.h" |
||
30 |
#include "tls_wrap.h" // TLSWrap |
||
31 |
|||
32 |
#include "async_wrap-inl.h" |
||
33 |
#include "base_object-inl.h" |
||
34 |
#include "env-inl.h" |
||
35 |
#include "memory_tracker-inl.h" |
||
36 |
#include "string_bytes.h" |
||
37 |
#include "threadpoolwork-inl.h" |
||
38 |
#include "util-inl.h" |
||
39 |
#include "v8.h" |
||
40 |
|||
41 |
#include <openssl/ec.h> |
||
42 |
#include <openssl/ecdh.h> |
||
43 |
#ifndef OPENSSL_NO_ENGINE |
||
44 |
# include <openssl/engine.h> |
||
45 |
#endif // !OPENSSL_NO_ENGINE |
||
46 |
#include <openssl/evp.h> |
||
47 |
#include <openssl/pem.h> |
||
48 |
#include <openssl/x509v3.h> |
||
49 |
#include <openssl/hmac.h> |
||
50 |
#include <openssl/rand.h> |
||
51 |
#include <openssl/pkcs12.h> |
||
52 |
|||
53 |
#include <cerrno> |
||
54 |
#include <climits> // INT_MAX |
||
55 |
#include <cstring> |
||
56 |
|||
57 |
#include <algorithm> |
||
58 |
#include <memory> |
||
59 |
#include <utility> |
||
60 |
#include <vector> |
||
61 |
|||
62 |
static const int X509_NAME_FLAGS = ASN1_STRFLGS_ESC_CTRL |
||
63 |
| ASN1_STRFLGS_UTF8_CONVERT |
||
64 |
| XN_FLAG_SEP_MULTILINE |
||
65 |
| XN_FLAG_FN_SN; |
||
66 |
|||
67 |
namespace node { |
||
68 |
namespace crypto { |
||
69 |
|||
70 |
using node::THROW_ERR_TLS_INVALID_PROTOCOL_METHOD; |
||
71 |
|||
72 |
using v8::Array; |
||
73 |
using v8::ArrayBufferView; |
||
74 |
using v8::Boolean; |
||
75 |
using v8::ConstructorBehavior; |
||
76 |
using v8::Context; |
||
77 |
using v8::DontDelete; |
||
78 |
using v8::EscapableHandleScope; |
||
79 |
using v8::Exception; |
||
80 |
using v8::External; |
||
81 |
using v8::False; |
||
82 |
using v8::Function; |
||
83 |
using v8::FunctionCallback; |
||
84 |
using v8::FunctionCallbackInfo; |
||
85 |
using v8::FunctionTemplate; |
||
86 |
using v8::HandleScope; |
||
87 |
using v8::Int32; |
||
88 |
using v8::Integer; |
||
89 |
using v8::Isolate; |
||
90 |
using v8::Just; |
||
91 |
using v8::Local; |
||
92 |
using v8::Maybe; |
||
93 |
using v8::MaybeLocal; |
||
94 |
using v8::NewStringType; |
||
95 |
using v8::Nothing; |
||
96 |
using v8::Null; |
||
97 |
using v8::Object; |
||
98 |
using v8::PropertyAttribute; |
||
99 |
using v8::ReadOnly; |
||
100 |
using v8::SideEffectType; |
||
101 |
using v8::Signature; |
||
102 |
using v8::String; |
||
103 |
using v8::Uint32; |
||
104 |
using v8::Undefined; |
||
105 |
using v8::Value; |
||
106 |
|||
107 |
#ifdef OPENSSL_NO_OCB |
||
108 |
# define IS_OCB_MODE(mode) false |
||
109 |
#else |
||
110 |
# define IS_OCB_MODE(mode) ((mode) == EVP_CIPH_OCB_MODE) |
||
111 |
#endif |
||
112 |
|||
113 |
struct StackOfX509Deleter { |
||
114 |
1291 |
void operator()(STACK_OF(X509)* p) const { sk_X509_pop_free(p, X509_free); } |
|
115 |
}; |
||
116 |
using StackOfX509 = std::unique_ptr<STACK_OF(X509), StackOfX509Deleter>; |
||
117 |
|||
118 |
struct StackOfXASN1Deleter { |
||
119 |
150 |
void operator()(STACK_OF(ASN1_OBJECT)* p) const { |
|
120 |
150 |
sk_ASN1_OBJECT_pop_free(p, ASN1_OBJECT_free); |
|
121 |
150 |
} |
|
122 |
}; |
||
123 |
using StackOfASN1 = std::unique_ptr<STACK_OF(ASN1_OBJECT), StackOfXASN1Deleter>; |
||
124 |
|||
125 |
// OPENSSL_free is a macro, so we need a wrapper function. |
||
126 |
struct OpenSSLBufferDeleter { |
||
127 |
1358 |
void operator()(char* pointer) const { OPENSSL_free(pointer); } |
|
128 |
}; |
||
129 |
using OpenSSLBuffer = std::unique_ptr<char[], OpenSSLBufferDeleter>; |
||
130 |
|||
131 |
static const char* const root_certs[] = { |
||
132 |
#include "node_root_certs.h" // NOLINT(build/include_order) |
||
133 |
}; |
||
134 |
|||
135 |
static const char system_cert_path[] = NODE_OPENSSL_SYSTEM_CERT_PATH; |
||
136 |
|||
137 |
static X509_STORE* root_cert_store; |
||
138 |
|||
139 |
static bool extra_root_certs_loaded = false; |
||
140 |
|||
141 |
// Just to generate static methods |
||
142 |
template void SSLWrap<TLSWrap>::AddMethods(Environment* env, |
||
143 |
Local<FunctionTemplate> t); |
||
144 |
template void SSLWrap<TLSWrap>::ConfigureSecureContext(SecureContext* sc); |
||
145 |
template void SSLWrap<TLSWrap>::SetSNIContext(SecureContext* sc); |
||
146 |
template int SSLWrap<TLSWrap>::SetCACerts(SecureContext* sc); |
||
147 |
template SSL_SESSION* SSLWrap<TLSWrap>::GetSessionCallback( |
||
148 |
SSL* s, |
||
149 |
const unsigned char* key, |
||
150 |
int len, |
||
151 |
int* copy); |
||
152 |
template int SSLWrap<TLSWrap>::NewSessionCallback(SSL* s, |
||
153 |
SSL_SESSION* sess); |
||
154 |
template void SSLWrap<TLSWrap>::KeylogCallback(const SSL* s, |
||
155 |
const char* line); |
||
156 |
template void SSLWrap<TLSWrap>::OnClientHello( |
||
157 |
void* arg, |
||
158 |
const ClientHelloParser::ClientHello& hello); |
||
159 |
template int SSLWrap<TLSWrap>::TLSExtStatusCallback(SSL* s, void* arg); |
||
160 |
template void SSLWrap<TLSWrap>::DestroySSL(); |
||
161 |
template int SSLWrap<TLSWrap>::SSLCertCallback(SSL* s, void* arg); |
||
162 |
template void SSLWrap<TLSWrap>::WaitForCertCb(CertCb cb, void* arg); |
||
163 |
template int SSLWrap<TLSWrap>::SelectALPNCallback( |
||
164 |
SSL* s, |
||
165 |
const unsigned char** out, |
||
166 |
unsigned char* outlen, |
||
167 |
const unsigned char* in, |
||
168 |
unsigned int inlen, |
||
169 |
void* arg); |
||
170 |
|||
171 |
93 |
static int PasswordCallback(char* buf, int size, int rwflag, void* u) { |
|
172 |
93 |
const char* passphrase = static_cast<char*>(u); |
|
173 |
✓✓ | 93 |
if (passphrase != nullptr) { |
174 |
85 |
size_t buflen = static_cast<size_t>(size); |
|
175 |
85 |
size_t len = strlen(passphrase); |
|
176 |
✓✓ | 85 |
if (buflen < len) |
177 |
1 |
return -1; |
|
178 |
84 |
memcpy(buf, passphrase, len); |
|
179 |
84 |
return len; |
|
180 |
} |
||
181 |
|||
182 |
8 |
return -1; |
|
183 |
} |
||
184 |
|||
185 |
// Loads OpenSSL engine by engine id and returns it. The loaded engine |
||
186 |
// gets a reference so remember the corresponding call to ENGINE_free. |
||
187 |
// In case of error the appropriate js exception is scheduled |
||
188 |
// and nullptr is returned. |
||
189 |
#ifndef OPENSSL_NO_ENGINE |
||
190 |
2 |
static ENGINE* LoadEngineById(const char* engine_id, char (*errmsg)[1024]) { |
|
191 |
2 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
|
192 |
|||
193 |
2 |
ENGINE* engine = ENGINE_by_id(engine_id); |
|
194 |
|||
195 |
✓✗ | 2 |
if (engine == nullptr) { |
196 |
// Engine not found, try loading dynamically. |
||
197 |
2 |
engine = ENGINE_by_id("dynamic"); |
|
198 |
✓✗ | 2 |
if (engine != nullptr) { |
199 |
✓✗✓✗ ✓✗ |
4 |
if (!ENGINE_ctrl_cmd_string(engine, "SO_PATH", engine_id, 0) || |
200 |
2 |
!ENGINE_ctrl_cmd_string(engine, "LOAD", nullptr, 0)) { |
|
201 |
2 |
ENGINE_free(engine); |
|
202 |
2 |
engine = nullptr; |
|
203 |
} |
||
204 |
} |
||
205 |
} |
||
206 |
|||
207 |
✓✗ | 2 |
if (engine == nullptr) { |
208 |
2 |
int err = ERR_get_error(); |
|
209 |
✓✗ | 2 |
if (err != 0) { |
210 |
2 |
ERR_error_string_n(err, *errmsg, sizeof(*errmsg)); |
|
211 |
} else { |
||
212 |
snprintf(*errmsg, sizeof(*errmsg), |
||
213 |
"Engine \"%s\" was not found", engine_id); |
||
214 |
} |
||
215 |
} |
||
216 |
|||
217 |
2 |
return engine; |
|
218 |
} |
||
219 |
#endif // !OPENSSL_NO_ENGINE |
||
220 |
|||
221 |
// This callback is used to avoid the default passphrase callback in OpenSSL |
||
222 |
// which will typically prompt for the passphrase. The prompting is designed |
||
223 |
// for the OpenSSL CLI, but works poorly for Node.js because it involves |
||
224 |
// synchronous interaction with the controlling terminal, something we never |
||
225 |
// want, and use this function to avoid it. |
||
226 |
static int NoPasswordCallback(char* buf, int size, int rwflag, void* u) { |
||
227 |
return 0; |
||
228 |
} |
||
229 |
|||
230 |
|||
231 |
// namespace node::crypto::error |
||
232 |
namespace error { |
||
233 |
60 |
Maybe<bool> Decorate(Environment* env, Local<Object> obj, |
|
234 |
unsigned long err) { // NOLINT(runtime/int) |
||
235 |
✓✓ | 60 |
if (err == 0) return Just(true); // No decoration necessary. |
236 |
|||
237 |
49 |
const char* ls = ERR_lib_error_string(err); |
|
238 |
49 |
const char* fs = ERR_func_error_string(err); |
|
239 |
49 |
const char* rs = ERR_reason_error_string(err); |
|
240 |
|||
241 |
49 |
Isolate* isolate = env->isolate(); |
|
242 |
49 |
Local<Context> context = isolate->GetCurrentContext(); |
|
243 |
|||
244 |
✓✗ | 49 |
if (ls != nullptr) { |
245 |
✓✓ | 98 |
if (obj->Set(context, env->library_string(), |
246 |
196 |
OneByteString(isolate, ls)).IsNothing()) { |
|
247 |
1 |
return Nothing<bool>(); |
|
248 |
} |
||
249 |
} |
||
250 |
✓✗ | 48 |
if (fs != nullptr) { |
251 |
✗✓ | 96 |
if (obj->Set(context, env->function_string(), |
252 |
192 |
OneByteString(isolate, fs)).IsNothing()) { |
|
253 |
return Nothing<bool>(); |
||
254 |
} |
||
255 |
} |
||
256 |
✓✗ | 48 |
if (rs != nullptr) { |
257 |
✗✓ | 96 |
if (obj->Set(context, env->reason_string(), |
258 |
192 |
OneByteString(isolate, rs)).IsNothing()) { |
|
259 |
return Nothing<bool>(); |
||
260 |
} |
||
261 |
|||
262 |
// SSL has no API to recover the error name from the number, so we |
||
263 |
// transform reason strings like "this error" to "ERR_SSL_THIS_ERROR", |
||
264 |
// which ends up being close to the original error macro name. |
||
265 |
48 |
std::string reason(rs); |
|
266 |
|||
267 |
✓✓ | 906 |
for (auto& c : reason) { |
268 |
✓✓ | 858 |
if (c == ' ') |
269 |
104 |
c = '_'; |
|
270 |
else |
||
271 |
754 |
c = ToUpper(c); |
|
272 |
} |
||
273 |
|||
274 |
#define OSSL_ERROR_CODES_MAP(V) \ |
||
275 |
V(SYS) \ |
||
276 |
V(BN) \ |
||
277 |
V(RSA) \ |
||
278 |
V(DH) \ |
||
279 |
V(EVP) \ |
||
280 |
V(BUF) \ |
||
281 |
V(OBJ) \ |
||
282 |
V(PEM) \ |
||
283 |
V(DSA) \ |
||
284 |
V(X509) \ |
||
285 |
V(ASN1) \ |
||
286 |
V(CONF) \ |
||
287 |
V(CRYPTO) \ |
||
288 |
V(EC) \ |
||
289 |
V(SSL) \ |
||
290 |
V(BIO) \ |
||
291 |
V(PKCS7) \ |
||
292 |
V(X509V3) \ |
||
293 |
V(PKCS12) \ |
||
294 |
V(RAND) \ |
||
295 |
V(DSO) \ |
||
296 |
V(ENGINE) \ |
||
297 |
V(OCSP) \ |
||
298 |
V(UI) \ |
||
299 |
V(COMP) \ |
||
300 |
V(ECDSA) \ |
||
301 |
V(ECDH) \ |
||
302 |
V(OSSL_STORE) \ |
||
303 |
V(FIPS) \ |
||
304 |
V(CMS) \ |
||
305 |
V(TS) \ |
||
306 |
V(HMAC) \ |
||
307 |
V(CT) \ |
||
308 |
V(ASYNC) \ |
||
309 |
V(KDF) \ |
||
310 |
V(SM2) \ |
||
311 |
V(USER) \ |
||
312 |
|||
313 |
#define V(name) case ERR_LIB_##name: lib = #name "_"; break; |
||
314 |
48 |
const char* lib = ""; |
|
315 |
48 |
const char* prefix = "OSSL_"; |
|
316 |
✗✗✓✗ ✓✗✗✓ ✗✓✓✗ ✗✗✓✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗ |
48 |
switch (ERR_GET_LIB(err)) { OSSL_ERROR_CODES_MAP(V) } |
317 |
#undef V |
||
318 |
#undef OSSL_ERROR_CODES_MAP |
||
319 |
// Don't generate codes like "ERR_OSSL_SSL_". |
||
320 |
✓✗✓✓ |
48 |
if (lib && strcmp(lib, "SSL_") == 0) |
321 |
7 |
prefix = ""; |
|
322 |
|||
323 |
// All OpenSSL reason strings fit in a single 80-column macro definition, |
||
324 |
// all prefix lengths are <= 10, and ERR_OSSL_ is 9, so 128 is more than |
||
325 |
// sufficient. |
||
326 |
char code[128]; |
||
327 |
48 |
snprintf(code, sizeof(code), "ERR_%s%s%s", prefix, lib, reason.c_str()); |
|
328 |
|||
329 |
✗✓ | 96 |
if (obj->Set(env->isolate()->GetCurrentContext(), |
330 |
env->code_string(), |
||
331 |
240 |
OneByteString(env->isolate(), code)).IsNothing()) |
|
332 |
return Nothing<bool>(); |
||
333 |
} |
||
334 |
|||
335 |
48 |
return Just(true); |
|
336 |
} |
||
337 |
} // namespace error |
||
338 |
|||
339 |
|||
340 |
812 |
struct CryptoErrorVector : public std::vector<std::string> { |
|
341 |
73 |
inline void Capture() { |
|
342 |
73 |
clear(); |
|
343 |
✓✓ | 102 |
while (auto err = ERR_get_error()) { |
344 |
char buf[256]; |
||
345 |
29 |
ERR_error_string_n(err, buf, sizeof(buf)); |
|
346 |
29 |
push_back(buf); |
|
347 |
} |
||
348 |
29 |
std::reverse(begin(), end()); |
|
349 |
73 |
} |
|
350 |
|||
351 |
77 |
inline MaybeLocal<Value> ToException( |
|
352 |
Environment* env, |
||
353 |
Local<String> exception_string = Local<String>()) const { |
||
354 |
✓✓ | 77 |
if (exception_string.IsEmpty()) { |
355 |
8 |
CryptoErrorVector copy(*this); |
|
356 |
✗✓ | 8 |
if (copy.empty()) copy.push_back("no error"); // But possibly a bug... |
357 |
// Use last element as the error message, everything else goes |
||
358 |
// into the .opensslErrorStack property on the exception object. |
||
359 |
auto exception_string = |
||
360 |
8 |
String::NewFromUtf8(env->isolate(), copy.back().data(), |
|
361 |
16 |
NewStringType::kNormal, copy.back().size()) |
|
362 |
16 |
.ToLocalChecked(); |
|
363 |
8 |
copy.pop_back(); |
|
364 |
8 |
return copy.ToException(env, exception_string); |
|
365 |
} |
||
366 |
|||
367 |
69 |
Local<Value> exception_v = Exception::Error(exception_string); |
|
368 |
✗✓ | 69 |
CHECK(!exception_v.IsEmpty()); |
369 |
|||
370 |
✓✓ | 69 |
if (!empty()) { |
371 |
✗✓ | 17 |
CHECK(exception_v->IsObject()); |
372 |
17 |
Local<Object> exception = exception_v.As<Object>(); |
|
373 |
Maybe<bool> ok = exception->Set(env->context(), |
||
374 |
env->openssl_error_stack(), |
||
375 |
68 |
ToV8Value(env->context(), *this).ToLocalChecked()); |
|
376 |
✓✓ | 17 |
if (ok.IsNothing()) |
377 |
1 |
return MaybeLocal<Value>(); |
|
378 |
} |
||
379 |
|||
380 |
68 |
return exception_v; |
|
381 |
} |
||
382 |
}; |
||
383 |
|||
384 |
|||
385 |
61 |
void ThrowCryptoError(Environment* env, |
|
386 |
unsigned long err, // NOLINT(runtime/int) |
||
387 |
// Default, only used if there is no SSL `err` which can |
||
388 |
// be used to create a long-style message string. |
||
389 |
const char* message = nullptr) { |
||
390 |
61 |
char message_buffer[128] = {0}; |
|
391 |
✓✓✗✓ |
61 |
if (err != 0 || message == nullptr) { |
392 |
50 |
ERR_error_string_n(err, message_buffer, sizeof(message_buffer)); |
|
393 |
50 |
message = message_buffer; |
|
394 |
} |
||
395 |
61 |
HandleScope scope(env->isolate()); |
|
396 |
Local<String> exception_string = |
||
397 |
61 |
String::NewFromUtf8(env->isolate(), message, NewStringType::kNormal) |
|
398 |
122 |
.ToLocalChecked(); |
|
399 |
✓✓ | 120 |
CryptoErrorVector errors; |
400 |
61 |
errors.Capture(); |
|
401 |
Local<Value> exception; |
||
402 |
✓✓ | 122 |
if (!errors.ToException(env, exception_string).ToLocal(&exception)) |
403 |
1 |
return; |
|
404 |
Local<Object> obj; |
||
405 |
✗✓ | 180 |
if (!exception->ToObject(env->context()).ToLocal(&obj)) |
406 |
return; |
||
407 |
✓✓ | 120 |
if (error::Decorate(env, obj, err).IsNothing()) |
408 |
1 |
return; |
|
409 |
✓✓ | 118 |
env->isolate()->ThrowException(exception); |
410 |
} |
||
411 |
|||
412 |
|||
413 |
// Ensure that OpenSSL has enough entropy (at least 256 bits) for its PRNG. |
||
414 |
// The entropy pool starts out empty and needs to fill up before the PRNG |
||
415 |
// can be used securely. Once the pool is filled, it never dries up again; |
||
416 |
// its contents is stirred and reused when necessary. |
||
417 |
// |
||
418 |
// OpenSSL normally fills the pool automatically but not when someone starts |
||
419 |
// generating random numbers before the pool is full: in that case OpenSSL |
||
420 |
// keeps lowering the entropy estimate to thwart attackers trying to guess |
||
421 |
// the initial state of the PRNG. |
||
422 |
// |
||
423 |
// When that happens, we will have to wait until enough entropy is available. |
||
424 |
// That should normally never take longer than a few milliseconds. |
||
425 |
// |
||
426 |
// OpenSSL draws from /dev/random and /dev/urandom. While /dev/random may |
||
427 |
// block pending "true" randomness, /dev/urandom is a CSPRNG that doesn't |
||
428 |
// block under normal circumstances. |
||
429 |
// |
||
430 |
// The only time when /dev/urandom may conceivably block is right after boot, |
||
431 |
// when the whole system is still low on entropy. That's not something we can |
||
432 |
// do anything about. |
||
433 |
10548 |
inline void CheckEntropy() { |
|
434 |
for (;;) { |
||
435 |
10548 |
int status = RAND_status(); |
|
436 |
✗✓ | 10548 |
CHECK_GE(status, 0); // Cannot fail. |
437 |
✓✗ | 10548 |
if (status != 0) |
438 |
21096 |
break; |
|
439 |
|||
440 |
// Give up, RAND_poll() not supported. |
||
441 |
if (RAND_poll() == 0) |
||
442 |
break; |
||
443 |
} |
||
444 |
10548 |
} |
|
445 |
|||
446 |
|||
447 |
10251 |
bool EntropySource(unsigned char* buffer, size_t length) { |
|
448 |
// Ensure that OpenSSL's PRNG is properly seeded. |
||
449 |
10251 |
CheckEntropy(); |
|
450 |
// RAND_bytes() can return 0 to indicate that the entropy data is not truly |
||
451 |
// random. That's okay, it's still better than V8's stock source of entropy, |
||
452 |
// which is /dev/urandom on UNIX platforms and the current time on Windows. |
||
453 |
10251 |
return RAND_bytes(buffer, length) != -1; |
|
454 |
} |
||
455 |
|||
456 |
|||
457 |
template <typename T> |
||
458 |
405050 |
static T* MallocOpenSSL(size_t count) { |
|
459 |
405050 |
void* mem = OPENSSL_malloc(MultiplyWithOverflowCheck(count, sizeof(T))); |
|
460 |
✗✓✗✗ ✗✓✓✓ ✗✓✗✓ |
405050 |
CHECK_IMPLIES(mem == nullptr, count == 0); |
461 |
405050 |
return static_cast<T*>(mem); |
|
462 |
} |
||
463 |
|||
464 |
|||
465 |
686 |
void SecureContext::Initialize(Environment* env, Local<Object> target) { |
|
466 |
686 |
Local<FunctionTemplate> t = env->NewFunctionTemplate(New); |
|
467 |
1372 |
t->InstanceTemplate()->SetInternalFieldCount(1); |
|
468 |
Local<String> secureContextString = |
||
469 |
686 |
FIXED_ONE_BYTE_STRING(env->isolate(), "SecureContext"); |
|
470 |
686 |
t->SetClassName(secureContextString); |
|
471 |
|||
472 |
686 |
env->SetProtoMethod(t, "init", Init); |
|
473 |
686 |
env->SetProtoMethod(t, "setKey", SetKey); |
|
474 |
686 |
env->SetProtoMethod(t, "setCert", SetCert); |
|
475 |
686 |
env->SetProtoMethod(t, "addCACert", AddCACert); |
|
476 |
686 |
env->SetProtoMethod(t, "addCRL", AddCRL); |
|
477 |
686 |
env->SetProtoMethod(t, "addRootCerts", AddRootCerts); |
|
478 |
686 |
env->SetProtoMethod(t, "setCipherSuites", SetCipherSuites); |
|
479 |
686 |
env->SetProtoMethod(t, "setCiphers", SetCiphers); |
|
480 |
686 |
env->SetProtoMethod(t, "setECDHCurve", SetECDHCurve); |
|
481 |
686 |
env->SetProtoMethod(t, "setDHParam", SetDHParam); |
|
482 |
686 |
env->SetProtoMethod(t, "setMaxProto", SetMaxProto); |
|
483 |
686 |
env->SetProtoMethod(t, "setMinProto", SetMinProto); |
|
484 |
686 |
env->SetProtoMethod(t, "getMaxProto", GetMaxProto); |
|
485 |
686 |
env->SetProtoMethod(t, "getMinProto", GetMinProto); |
|
486 |
686 |
env->SetProtoMethod(t, "setOptions", SetOptions); |
|
487 |
686 |
env->SetProtoMethod(t, "setSessionIdContext", SetSessionIdContext); |
|
488 |
686 |
env->SetProtoMethod(t, "setSessionTimeout", SetSessionTimeout); |
|
489 |
686 |
env->SetProtoMethod(t, "close", Close); |
|
490 |
686 |
env->SetProtoMethod(t, "loadPKCS12", LoadPKCS12); |
|
491 |
#ifndef OPENSSL_NO_ENGINE |
||
492 |
686 |
env->SetProtoMethod(t, "setClientCertEngine", SetClientCertEngine); |
|
493 |
#endif // !OPENSSL_NO_ENGINE |
||
494 |
686 |
env->SetProtoMethodNoSideEffect(t, "getTicketKeys", GetTicketKeys); |
|
495 |
686 |
env->SetProtoMethod(t, "setTicketKeys", SetTicketKeys); |
|
496 |
686 |
env->SetProtoMethod(t, "setFreeListLength", SetFreeListLength); |
|
497 |
686 |
env->SetProtoMethod(t, "enableTicketKeyCallback", EnableTicketKeyCallback); |
|
498 |
686 |
env->SetProtoMethodNoSideEffect(t, "getCertificate", GetCertificate<true>); |
|
499 |
686 |
env->SetProtoMethodNoSideEffect(t, "getIssuer", GetCertificate<false>); |
|
500 |
|||
501 |
#define SET_INTEGER_CONSTANTS(name, value) \ |
||
502 |
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), name), \ |
||
503 |
Integer::NewFromUnsigned(env->isolate(), value)); |
||
504 |
2058 |
SET_INTEGER_CONSTANTS("kTicketKeyReturnIndex", kTicketKeyReturnIndex); |
|
505 |
2058 |
SET_INTEGER_CONSTANTS("kTicketKeyHMACIndex", kTicketKeyHMACIndex); |
|
506 |
2058 |
SET_INTEGER_CONSTANTS("kTicketKeyAESIndex", kTicketKeyAESIndex); |
|
507 |
2058 |
SET_INTEGER_CONSTANTS("kTicketKeyNameIndex", kTicketKeyNameIndex); |
|
508 |
2058 |
SET_INTEGER_CONSTANTS("kTicketKeyIVIndex", kTicketKeyIVIndex); |
|
509 |
|||
510 |
#undef SET_INTEGER_CONSTANTS |
||
511 |
|||
512 |
Local<FunctionTemplate> ctx_getter_templ = |
||
513 |
FunctionTemplate::New(env->isolate(), |
||
514 |
CtxGetter, |
||
515 |
env->as_callback_data(), |
||
516 |
1372 |
Signature::New(env->isolate(), t)); |
|
517 |
|||
518 |
|||
519 |
2058 |
t->PrototypeTemplate()->SetAccessorProperty( |
|
520 |
FIXED_ONE_BYTE_STRING(env->isolate(), "_external"), |
||
521 |
ctx_getter_templ, |
||
522 |
Local<FunctionTemplate>(), |
||
523 |
2058 |
static_cast<PropertyAttribute>(ReadOnly | DontDelete)); |
|
524 |
|||
525 |
target->Set(env->context(), secureContextString, |
||
526 |
3430 |
t->GetFunction(env->context()).ToLocalChecked()).Check(); |
|
527 |
686 |
env->set_secure_context_constructor_template(t); |
|
528 |
686 |
} |
|
529 |
|||
530 |
|||
531 |
2343 |
void SecureContext::New(const FunctionCallbackInfo<Value>& args) { |
|
532 |
2343 |
Environment* env = Environment::GetCurrent(args); |
|
533 |
2343 |
new SecureContext(env, args.This()); |
|
534 |
2343 |
} |
|
535 |
|||
536 |
// A maxVersion of 0 means "any", but OpenSSL may support TLS versions that |
||
537 |
// Node.js doesn't, so pin the max to what we do support. |
||
538 |
const int MAX_SUPPORTED_VERSION = TLS1_3_VERSION; |
||
539 |
|||
540 |
2343 |
void SecureContext::Init(const FunctionCallbackInfo<Value>& args) { |
|
541 |
SecureContext* sc; |
||
542 |
✗✓ | 2392 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
543 |
2343 |
Environment* env = sc->env(); |
|
544 |
|||
545 |
✗✓ | 2343 |
CHECK_EQ(args.Length(), 3); |
546 |
✗✓ | 4686 |
CHECK(args[1]->IsInt32()); |
547 |
✗✓ | 4686 |
CHECK(args[2]->IsInt32()); |
548 |
|||
549 |
7029 |
int min_version = args[1].As<Int32>()->Value(); |
|
550 |
7029 |
int max_version = args[2].As<Int32>()->Value(); |
|
551 |
2343 |
const SSL_METHOD* method = TLS_method(); |
|
552 |
|||
553 |
✗✓ | 2343 |
if (max_version == 0) |
554 |
max_version = MAX_SUPPORTED_VERSION; |
||
555 |
|||
556 |
✓✓ | 7029 |
if (args[0]->IsString()) { |
557 |
362 |
const node::Utf8Value sslmethod(env->isolate(), args[0]); |
|
558 |
|||
559 |
// Note that SSLv2 and SSLv3 are disallowed but SSLv23_method and friends |
||
560 |
// are still accepted. They are OpenSSL's way of saying that all known |
||
561 |
// protocols below TLS 1.3 are supported unless explicitly disabled (which |
||
562 |
// we do below for SSLv2 and SSLv3.) |
||
563 |
✓✓ | 362 |
if (strcmp(*sslmethod, "SSLv2_method") == 0) { |
564 |
15 |
THROW_ERR_TLS_INVALID_PROTOCOL_METHOD(env, "SSLv2 methods disabled"); |
|
565 |
15 |
return; |
|
566 |
✓✓ | 347 |
} else if (strcmp(*sslmethod, "SSLv2_server_method") == 0) { |
567 |
1 |
THROW_ERR_TLS_INVALID_PROTOCOL_METHOD(env, "SSLv2 methods disabled"); |
|
568 |
1 |
return; |
|
569 |
✓✓ | 346 |
} else if (strcmp(*sslmethod, "SSLv2_client_method") == 0) { |
570 |
1 |
THROW_ERR_TLS_INVALID_PROTOCOL_METHOD(env, "SSLv2 methods disabled"); |
|
571 |
1 |
return; |
|
572 |
✓✓ | 345 |
} else if (strcmp(*sslmethod, "SSLv3_method") == 0) { |
573 |
15 |
THROW_ERR_TLS_INVALID_PROTOCOL_METHOD(env, "SSLv3 methods disabled"); |
|
574 |
15 |
return; |
|
575 |
✓✓ | 330 |
} else if (strcmp(*sslmethod, "SSLv3_server_method") == 0) { |
576 |
1 |
THROW_ERR_TLS_INVALID_PROTOCOL_METHOD(env, "SSLv3 methods disabled"); |
|
577 |
1 |
return; |
|
578 |
✓✓ | 329 |
} else if (strcmp(*sslmethod, "SSLv3_client_method") == 0) { |
579 |
1 |
THROW_ERR_TLS_INVALID_PROTOCOL_METHOD(env, "SSLv3 methods disabled"); |
|
580 |
1 |
return; |
|
581 |
✓✓ | 328 |
} else if (strcmp(*sslmethod, "SSLv23_method") == 0) { |
582 |
36 |
max_version = TLS1_2_VERSION; |
|
583 |
✓✓ | 292 |
} else if (strcmp(*sslmethod, "SSLv23_server_method") == 0) { |
584 |
1 |
max_version = TLS1_2_VERSION; |
|
585 |
1 |
method = TLS_server_method(); |
|
586 |
✓✓ | 291 |
} else if (strcmp(*sslmethod, "SSLv23_client_method") == 0) { |
587 |
1 |
max_version = TLS1_2_VERSION; |
|
588 |
1 |
method = TLS_client_method(); |
|
589 |
✓✓ | 290 |
} else if (strcmp(*sslmethod, "TLS_method") == 0) { |
590 |
53 |
min_version = 0; |
|
591 |
53 |
max_version = MAX_SUPPORTED_VERSION; |
|
592 |
✗✓ | 237 |
} else if (strcmp(*sslmethod, "TLS_server_method") == 0) { |
593 |
min_version = 0; |
||
594 |
max_version = MAX_SUPPORTED_VERSION; |
||
595 |
method = TLS_server_method(); |
||
596 |
✗✓ | 237 |
} else if (strcmp(*sslmethod, "TLS_client_method") == 0) { |
597 |
min_version = 0; |
||
598 |
max_version = MAX_SUPPORTED_VERSION; |
||
599 |
method = TLS_client_method(); |
||
600 |
✓✓ | 237 |
} else if (strcmp(*sslmethod, "TLSv1_method") == 0) { |
601 |
71 |
min_version = TLS1_VERSION; |
|
602 |
71 |
max_version = TLS1_VERSION; |
|
603 |
✓✓ | 166 |
} else if (strcmp(*sslmethod, "TLSv1_server_method") == 0) { |
604 |
1 |
min_version = TLS1_VERSION; |
|
605 |
1 |
max_version = TLS1_VERSION; |
|
606 |
1 |
method = TLS_server_method(); |
|
607 |
✓✓ | 165 |
} else if (strcmp(*sslmethod, "TLSv1_client_method") == 0) { |
608 |
1 |
min_version = TLS1_VERSION; |
|
609 |
1 |
max_version = TLS1_VERSION; |
|
610 |
1 |
method = TLS_client_method(); |
|
611 |
✓✓ | 164 |
} else if (strcmp(*sslmethod, "TLSv1_1_method") == 0) { |
612 |
71 |
min_version = TLS1_1_VERSION; |
|
613 |
71 |
max_version = TLS1_1_VERSION; |
|
614 |
✓✓ | 93 |
} else if (strcmp(*sslmethod, "TLSv1_1_server_method") == 0) { |
615 |
1 |
min_version = TLS1_1_VERSION; |
|
616 |
1 |
max_version = TLS1_1_VERSION; |
|
617 |
1 |
method = TLS_server_method(); |
|
618 |
✓✓ | 92 |
} else if (strcmp(*sslmethod, "TLSv1_1_client_method") == 0) { |
619 |
1 |
min_version = TLS1_1_VERSION; |
|
620 |
1 |
max_version = TLS1_1_VERSION; |
|
621 |
1 |
method = TLS_client_method(); |
|
622 |
✓✓ | 91 |
} else if (strcmp(*sslmethod, "TLSv1_2_method") == 0) { |
623 |
73 |
min_version = TLS1_2_VERSION; |
|
624 |
73 |
max_version = TLS1_2_VERSION; |
|
625 |
✓✓ | 18 |
} else if (strcmp(*sslmethod, "TLSv1_2_server_method") == 0) { |
626 |
2 |
min_version = TLS1_2_VERSION; |
|
627 |
2 |
max_version = TLS1_2_VERSION; |
|
628 |
2 |
method = TLS_server_method(); |
|
629 |
✓✓ | 16 |
} else if (strcmp(*sslmethod, "TLSv1_2_client_method") == 0) { |
630 |
1 |
min_version = TLS1_2_VERSION; |
|
631 |
1 |
max_version = TLS1_2_VERSION; |
|
632 |
1 |
method = TLS_client_method(); |
|
633 |
} else { |
||
634 |
15 |
const std::string msg("Unknown method: "); |
|
635 |
15 |
THROW_ERR_TLS_INVALID_PROTOCOL_METHOD(env, (msg + * sslmethod).c_str()); |
|
636 |
✓✓ | 15 |
return; |
637 |
313 |
} |
|
638 |
} |
||
639 |
|||
640 |
2294 |
sc->ctx_.reset(SSL_CTX_new(method)); |
|
641 |
2294 |
SSL_CTX_set_app_data(sc->ctx_.get(), sc); |
|
642 |
|||
643 |
// Disable SSLv2 in the case when method == TLS_method() and the |
||
644 |
// cipher list contains SSLv2 ciphers (not the default, should be rare.) |
||
645 |
// The bundled OpenSSL doesn't have SSLv2 support but the system OpenSSL may. |
||
646 |
// SSLv3 is disabled because it's susceptible to downgrade attacks (POODLE.) |
||
647 |
2294 |
SSL_CTX_set_options(sc->ctx_.get(), SSL_OP_NO_SSLv2); |
|
648 |
2294 |
SSL_CTX_set_options(sc->ctx_.get(), SSL_OP_NO_SSLv3); |
|
649 |
|||
650 |
// Enable automatic cert chaining. This is enabled by default in OpenSSL, but |
||
651 |
// disabled by default in BoringSSL. Enable it explicitly to make the |
||
652 |
// behavior match when Node is built with BoringSSL. |
||
653 |
2294 |
SSL_CTX_clear_mode(sc->ctx_.get(), SSL_MODE_NO_AUTO_CHAIN); |
|
654 |
|||
655 |
// SSL session cache configuration |
||
656 |
2294 |
SSL_CTX_set_session_cache_mode(sc->ctx_.get(), |
|
657 |
SSL_SESS_CACHE_CLIENT | |
||
658 |
SSL_SESS_CACHE_SERVER | |
||
659 |
SSL_SESS_CACHE_NO_INTERNAL | |
||
660 |
2294 |
SSL_SESS_CACHE_NO_AUTO_CLEAR); |
|
661 |
|||
662 |
2294 |
SSL_CTX_set_min_proto_version(sc->ctx_.get(), min_version); |
|
663 |
2294 |
SSL_CTX_set_max_proto_version(sc->ctx_.get(), max_version); |
|
664 |
|||
665 |
// OpenSSL 1.1.0 changed the ticket key size, but the OpenSSL 1.0.x size was |
||
666 |
// exposed in the public API. To retain compatibility, install a callback |
||
667 |
// which restores the old algorithm. |
||
668 |
✓✗✗✓ |
6882 |
if (RAND_bytes(sc->ticket_key_name_, sizeof(sc->ticket_key_name_)) <= 0 || |
669 |
✓✗✗✓ |
4588 |
RAND_bytes(sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_)) <= 0 || |
670 |
2294 |
RAND_bytes(sc->ticket_key_aes_, sizeof(sc->ticket_key_aes_)) <= 0) { |
|
671 |
return env->ThrowError("Error generating ticket keys"); |
||
672 |
} |
||
673 |
2294 |
SSL_CTX_set_tlsext_ticket_key_cb(sc->ctx_.get(), TicketCompatibilityCallback); |
|
674 |
} |
||
675 |
|||
676 |
|||
677 |
// Takes a string or buffer and loads it into a BIO. |
||
678 |
// Caller responsible for BIO_free_all-ing the returned object. |
||
679 |
2219 |
static BIOPointer LoadBIO(Environment* env, Local<Value> v) { |
|
680 |
2219 |
HandleScope scope(env->isolate()); |
|
681 |
|||
682 |
✓✓ | 4438 |
if (v->IsString()) { |
683 |
1286 |
const node::Utf8Value s(env->isolate(), v); |
|
684 |
1286 |
return NodeBIO::NewFixed(*s, s.length()); |
|
685 |
} |
||
686 |
|||
687 |
✓✗ | 933 |
if (v->IsArrayBufferView()) { |
688 |
933 |
ArrayBufferViewContents<char> buf(v.As<ArrayBufferView>()); |
|
689 |
933 |
return NodeBIO::NewFixed(buf.data(), buf.length()); |
|
690 |
} |
||
691 |
|||
692 |
return nullptr; |
||
693 |
} |
||
694 |
|||
695 |
|||
696 |
814 |
void SecureContext::SetKey(const FunctionCallbackInfo<Value>& args) { |
|
697 |
814 |
Environment* env = Environment::GetCurrent(args); |
|
698 |
|||
699 |
SecureContext* sc; |
||
700 |
✗✓ | 824 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
701 |
|||
702 |
814 |
unsigned int len = args.Length(); |
|
703 |
✗✓ | 814 |
if (len < 1) { |
704 |
return THROW_ERR_MISSING_ARGS(env, "Private key argument is mandatory"); |
||
705 |
} |
||
706 |
|||
707 |
✗✓ | 814 |
if (len > 2) { |
708 |
return env->ThrowError("Only private key and pass phrase are expected"); |
||
709 |
} |
||
710 |
|||
711 |
✓✗ | 814 |
if (len == 2) { |
712 |
✓✓✗✓ ✓✓✓✗ ✓✓ |
3334 |
if (args[1]->IsUndefined() || args[1]->IsNull()) |
713 |
788 |
len = 1; |
|
714 |
else |
||
715 |
✓✓ | 78 |
THROW_AND_RETURN_IF_NOT_STRING(env, args[1], "Pass phrase"); |
716 |
} |
||
717 |
|||
718 |
812 |
BIOPointer bio(LoadBIO(env, args[0])); |
|
719 |
✗✓ | 812 |
if (!bio) |
720 |
return; |
||
721 |
|||
722 |
✓✓ | 1616 |
node::Utf8Value passphrase(env->isolate(), args[1]); |
723 |
|||
724 |
EVPKeyPointer key( |
||
725 |
PEM_read_bio_PrivateKey(bio.get(), |
||
726 |
nullptr, |
||
727 |
PasswordCallback, |
||
728 |
✓✓ | 1616 |
*passphrase)); |
729 |
|||
730 |
✓✓ | 812 |
if (!key) { |
731 |
7 |
unsigned long err = ERR_get_error(); // NOLINT(runtime/int) |
|
732 |
✗✓ | 7 |
if (!err) { |
733 |
return env->ThrowError("PEM_read_bio_PrivateKey"); |
||
734 |
} |
||
735 |
7 |
return ThrowCryptoError(env, err); |
|
736 |
} |
||
737 |
|||
738 |
805 |
int rv = SSL_CTX_use_PrivateKey(sc->ctx_.get(), key.get()); |
|
739 |
|||
740 |
✓✓ | 805 |
if (!rv) { |
741 |
1 |
unsigned long err = ERR_get_error(); // NOLINT(runtime/int) |
|
742 |
✗✓ | 1 |
if (!err) |
743 |
return env->ThrowError("SSL_CTX_use_PrivateKey"); |
||
744 |
✓✓ | 1 |
return ThrowCryptoError(env, err); |
745 |
804 |
} |
|
746 |
} |
||
747 |
|||
748 |
|||
749 |
861 |
int SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert, X509** issuer) { |
|
750 |
861 |
X509_STORE* store = SSL_CTX_get_cert_store(ctx); |
|
751 |
DeleteFnPtr<X509_STORE_CTX, X509_STORE_CTX_free> store_ctx( |
||
752 |
861 |
X509_STORE_CTX_new()); |
|
753 |
✓✗ | 1722 |
return store_ctx.get() != nullptr && |
754 |
✓✗✓✓ |
1722 |
X509_STORE_CTX_init(store_ctx.get(), store, nullptr, nullptr) == 1 && |
755 |
1722 |
X509_STORE_CTX_get1_issuer(issuer, store_ctx.get(), cert) == 1; |
|
756 |
} |
||
757 |
|||
758 |
|||
759 |
842 |
int SSL_CTX_use_certificate_chain(SSL_CTX* ctx, |
|
760 |
X509Pointer&& x, |
||
761 |
STACK_OF(X509)* extra_certs, |
||
762 |
X509Pointer* cert, |
||
763 |
X509Pointer* issuer_) { |
||
764 |
✗✓ | 842 |
CHECK(!*issuer_); |
765 |
✗✓ | 842 |
CHECK(!*cert); |
766 |
842 |
X509* issuer = nullptr; |
|
767 |
|||
768 |
842 |
int ret = SSL_CTX_use_certificate(ctx, x.get()); |
|
769 |
|||
770 |
✓✗ | 842 |
if (ret) { |
771 |
// If we could set up our certificate, now proceed to |
||
772 |
// the CA certificates. |
||
773 |
842 |
SSL_CTX_clear_extra_chain_certs(ctx); |
|
774 |
|||
775 |
✓✓ | 1253 |
for (int i = 0; i < sk_X509_num(extra_certs); i++) { |
776 |
411 |
X509* ca = sk_X509_value(extra_certs, i); |
|
777 |
|||
778 |
// NOTE: Increments reference count on `ca` |
||
779 |
✗✓ | 411 |
if (!SSL_CTX_add1_chain_cert(ctx, ca)) { |
780 |
ret = 0; |
||
781 |
issuer = nullptr; |
||
782 |
break; |
||
783 |
} |
||
784 |
// Note that we must not free r if it was successfully |
||
785 |
// added to the chain (while we must free the main |
||
786 |
// certificate, since its reference count is increased |
||
787 |
// by SSL_CTX_use_certificate). |
||
788 |
|||
789 |
// Find issuer |
||
790 |
✓✓✓✓ ✓✓ |
411 |
if (issuer != nullptr || X509_check_issued(ca, x.get()) != X509_V_OK) |
791 |
4 |
continue; |
|
792 |
|||
793 |
407 |
issuer = ca; |
|
794 |
} |
||
795 |
} |
||
796 |
|||
797 |
// Try getting issuer from a cert store |
||
798 |
✓✗ | 842 |
if (ret) { |
799 |
✓✓ | 842 |
if (issuer == nullptr) { |
800 |
435 |
ret = SSL_CTX_get_issuer(ctx, x.get(), &issuer); |
|
801 |
435 |
ret = ret < 0 ? 0 : 1; |
|
802 |
// NOTE: get_cert_store doesn't increment reference count, |
||
803 |
// no need to free `store` |
||
804 |
} else { |
||
805 |
// Increment issuer reference count |
||
806 |
407 |
issuer = X509_dup(issuer); |
|
807 |
✗✓ | 407 |
if (issuer == nullptr) { |
808 |
ret = 0; |
||
809 |
} |
||
810 |
} |
||
811 |
} |
||
812 |
|||
813 |
842 |
issuer_->reset(issuer); |
|
814 |
|||
815 |
✓✗✓✗ ✓✗ |
842 |
if (ret && x != nullptr) { |
816 |
842 |
cert->reset(X509_dup(x.get())); |
|
817 |
✗✓ | 842 |
if (!*cert) |
818 |
ret = 0; |
||
819 |
} |
||
820 |
842 |
return ret; |
|
821 |
} |
||
822 |
|||
823 |
|||
824 |
// Read a file that contains our certificate in "PEM" format, |
||
825 |
// possibly followed by a sequence of CA certificates that should be |
||
826 |
// sent to the peer in the Certificate message. |
||
827 |
// |
||
828 |
// Taken from OpenSSL - edited for style. |
||
829 |
830 |
int SSL_CTX_use_certificate_chain(SSL_CTX* ctx, |
|
830 |
BIOPointer&& in, |
||
831 |
X509Pointer* cert, |
||
832 |
X509Pointer* issuer) { |
||
833 |
// Just to ensure that `ERR_peek_last_error` below will return only errors |
||
834 |
// that we are interested in |
||
835 |
830 |
ERR_clear_error(); |
|
836 |
|||
837 |
X509Pointer x( |
||
838 |
830 |
PEM_read_bio_X509_AUX(in.get(), nullptr, NoPasswordCallback, nullptr)); |
|
839 |
|||
840 |
✗✓ | 830 |
if (!x) |
841 |
return 0; |
||
842 |
|||
843 |
830 |
unsigned long err = 0; // NOLINT(runtime/int) |
|
844 |
|||
845 |
1660 |
StackOfX509 extra_certs(sk_X509_new_null()); |
|
846 |
✗✓ | 830 |
if (!extra_certs) |
847 |
return 0; |
||
848 |
|||
849 |
while (X509Pointer extra {PEM_read_bio_X509(in.get(), |
||
850 |
nullptr, |
||
851 |
NoPasswordCallback, |
||
852 |
✓✓ | 1232 |
nullptr)}) { |
853 |
✓✗ | 402 |
if (sk_X509_push(extra_certs.get(), extra.get())) { |
854 |
402 |
extra.release(); |
|
855 |
402 |
continue; |
|
856 |
} |
||
857 |
|||
858 |
return 0; |
||
859 |
} |
||
860 |
|||
861 |
// When the while loop ends, it's usually just EOF. |
||
862 |
830 |
err = ERR_peek_last_error(); |
|
863 |
✓✗✓✗ |
1660 |
if (ERR_GET_LIB(err) == ERR_LIB_PEM && |
864 |
830 |
ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { |
|
865 |
830 |
ERR_clear_error(); |
|
866 |
} else { |
||
867 |
// some real error |
||
868 |
return 0; |
||
869 |
} |
||
870 |
|||
871 |
return SSL_CTX_use_certificate_chain(ctx, |
||
872 |
830 |
std::move(x), |
|
873 |
extra_certs.get(), |
||
874 |
cert, |
||
875 |
2490 |
issuer); |
|
876 |
} |
||
877 |
|||
878 |
|||
879 |
830 |
void SecureContext::SetCert(const FunctionCallbackInfo<Value>& args) { |
|
880 |
830 |
Environment* env = Environment::GetCurrent(args); |
|
881 |
|||
882 |
SecureContext* sc; |
||
883 |
✗✓ | 830 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
884 |
|||
885 |
✗✓ | 830 |
if (args.Length() != 1) { |
886 |
return THROW_ERR_MISSING_ARGS(env, "Certificate argument is mandatory"); |
||
887 |
} |
||
888 |
|||
889 |
830 |
BIOPointer bio(LoadBIO(env, args[0])); |
|
890 |
✗✓ | 830 |
if (!bio) |
891 |
return; |
||
892 |
|||
893 |
830 |
sc->cert_.reset(); |
|
894 |
830 |
sc->issuer_.reset(); |
|
895 |
|||
896 |
int rv = SSL_CTX_use_certificate_chain(sc->ctx_.get(), |
||
897 |
830 |
std::move(bio), |
|
898 |
&sc->cert_, |
||
899 |
1660 |
&sc->issuer_); |
|
900 |
|||
901 |
✗✓ | 830 |
if (!rv) { |
902 |
unsigned long err = ERR_get_error(); // NOLINT(runtime/int) |
||
903 |
if (!err) { |
||
904 |
return env->ThrowError("SSL_CTX_use_certificate_chain"); |
||
905 |
} |
||
906 |
return ThrowCryptoError(env, err); |
||
907 |
830 |
} |
|
908 |
} |
||
909 |
|||
910 |
|||
911 |
306 |
static X509_STORE* NewRootCertStore() { |
|
912 |
✓✓✓✗ |
306 |
static std::vector<X509*> root_certs_vector; |
913 |
✓✓✓✗ |
306 |
static Mutex root_certs_vector_mutex; |
914 |
306 |
Mutex::ScopedLock lock(root_certs_vector_mutex); |
|
915 |
|||
916 |
✓✓ | 306 |
if (root_certs_vector.empty()) { |
917 |
✓✓ | 41720 |
for (size_t i = 0; i < arraysize(root_certs); i++) { |
918 |
X509* x509 = |
||
919 |
41422 |
PEM_read_bio_X509(NodeBIO::NewFixed(root_certs[i], |
|
920 |
41422 |
strlen(root_certs[i])).get(), |
|
921 |
nullptr, // no re-use of X509 structure |
||
922 |
NoPasswordCallback, |
||
923 |
82844 |
nullptr); // no callback data |
|
924 |
|||
925 |
// Parse errors from the built-in roots are fatal. |
||
926 |
✗✓ | 41422 |
CHECK_NOT_NULL(x509); |
927 |
|||
928 |
41422 |
root_certs_vector.push_back(x509); |
|
929 |
} |
||
930 |
} |
||
931 |
|||
932 |
306 |
X509_STORE* store = X509_STORE_new(); |
|
933 |
✗✓ | 306 |
if (*system_cert_path != '\0') { |
934 |
X509_STORE_load_locations(store, system_cert_path, nullptr); |
||
935 |
} |
||
936 |
✗✓ | 306 |
if (per_process::cli_options->ssl_openssl_cert_store) { |
937 |
X509_STORE_set_default_paths(store); |
||
938 |
} else { |
||
939 |
✓✓ | 42840 |
for (X509* cert : root_certs_vector) { |
940 |
42534 |
X509_up_ref(cert); |
|
941 |
42534 |
X509_STORE_add_cert(store, cert); |
|
942 |
} |
||
943 |
} |
||
944 |
|||
945 |
306 |
return store; |
|
946 |
} |
||
947 |
|||
948 |
|||
949 |
1 |
void GetRootCertificates(const FunctionCallbackInfo<Value>& args) { |
|
950 |
1 |
Environment* env = Environment::GetCurrent(args); |
|
951 |
1 |
Local<Array> result = Array::New(env->isolate(), arraysize(root_certs)); |
|
952 |
|||
953 |
✓✓ | 140 |
for (size_t i = 0; i < arraysize(root_certs); i++) { |
954 |
Local<Value> value; |
||
955 |
✗✓ | 278 |
if (!String::NewFromOneByte(env->isolate(), |
956 |
139 |
reinterpret_cast<const uint8_t*>(root_certs[i]), |
|
957 |
✓✗✗✓ ✗✓ |
1112 |
NewStringType::kNormal).ToLocal(&value) || |
958 |
✓✗✓✗ |
695 |
!result->Set(env->context(), i, value).FromMaybe(false)) { |
959 |
1 |
return; |
|
960 |
} |
||
961 |
} |
||
962 |
|||
963 |
2 |
args.GetReturnValue().Set(result); |
|
964 |
} |
||
965 |
|||
966 |
|||
967 |
547 |
void SecureContext::AddCACert(const FunctionCallbackInfo<Value>& args) { |
|
968 |
547 |
Environment* env = Environment::GetCurrent(args); |
|
969 |
|||
970 |
SecureContext* sc; |
||
971 |
✗✓ | 547 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
972 |
ClearErrorOnReturn clear_error_on_return; |
||
973 |
|||
974 |
✗✓ | 547 |
if (args.Length() != 1) { |
975 |
return THROW_ERR_MISSING_ARGS(env, "CA certificate argument is mandatory"); |
||
976 |
} |
||
977 |
|||
978 |
✓✗ | 1094 |
BIOPointer bio(LoadBIO(env, args[0])); |
979 |
✗✓ | 547 |
if (!bio) |
980 |
return; |
||
981 |
|||
982 |
547 |
X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_.get()); |
|
983 |
while (X509* x509 = PEM_read_bio_X509_AUX( |
||
984 |
✓✓ | 1429 |
bio.get(), nullptr, NoPasswordCallback, nullptr)) { |
985 |
✓✓ | 882 |
if (cert_store == root_cert_store) { |
986 |
2 |
cert_store = NewRootCertStore(); |
|
987 |
2 |
SSL_CTX_set_cert_store(sc->ctx_.get(), cert_store); |
|
988 |
} |
||
989 |
882 |
X509_STORE_add_cert(cert_store, x509); |
|
990 |
882 |
SSL_CTX_add_client_CA(sc->ctx_.get(), x509); |
|
991 |
✓✗ | 882 |
X509_free(x509); |
992 |
547 |
} |
|
993 |
} |
||
994 |
|||
995 |
|||
996 |
2 |
void SecureContext::AddCRL(const FunctionCallbackInfo<Value>& args) { |
|
997 |
2 |
Environment* env = Environment::GetCurrent(args); |
|
998 |
|||
999 |
SecureContext* sc; |
||
1000 |
✗✓ | 3 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1001 |
|||
1002 |
✗✓ | 2 |
if (args.Length() != 1) { |
1003 |
return THROW_ERR_MISSING_ARGS(env, "CRL argument is mandatory"); |
||
1004 |
} |
||
1005 |
|||
1006 |
ClearErrorOnReturn clear_error_on_return; |
||
1007 |
|||
1008 |
✓✓ | 3 |
BIOPointer bio(LoadBIO(env, args[0])); |
1009 |
✗✓ | 2 |
if (!bio) |
1010 |
return; |
||
1011 |
|||
1012 |
DeleteFnPtr<X509_CRL, X509_CRL_free> crl( |
||
1013 |
✓✓ | 3 |
PEM_read_bio_X509_CRL(bio.get(), nullptr, NoPasswordCallback, nullptr)); |
1014 |
|||
1015 |
✓✓ | 2 |
if (!crl) |
1016 |
1 |
return env->ThrowError("Failed to parse CRL"); |
|
1017 |
|||
1018 |
1 |
X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_.get()); |
|
1019 |
✗✓ | 1 |
if (cert_store == root_cert_store) { |
1020 |
cert_store = NewRootCertStore(); |
||
1021 |
SSL_CTX_set_cert_store(sc->ctx_.get(), cert_store); |
||
1022 |
} |
||
1023 |
|||
1024 |
1 |
X509_STORE_add_crl(cert_store, crl.get()); |
|
1025 |
X509_STORE_set_flags(cert_store, |
||
1026 |
✓✓ | 2 |
X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); |
1027 |
} |
||
1028 |
|||
1029 |
|||
1030 |
3 |
static unsigned long AddCertsFromFile( // NOLINT(runtime/int) |
|
1031 |
X509_STORE* store, |
||
1032 |
const char* file) { |
||
1033 |
3 |
ERR_clear_error(); |
|
1034 |
3 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
|
1035 |
|||
1036 |
6 |
BIOPointer bio(BIO_new_file(file, "r")); |
|
1037 |
✓✓ | 3 |
if (!bio) |
1038 |
1 |
return ERR_get_error(); |
|
1039 |
|||
1040 |
while (X509* x509 = |
||
1041 |
✓✓ | 4 |
PEM_read_bio_X509(bio.get(), nullptr, NoPasswordCallback, nullptr)) { |
1042 |
2 |
X509_STORE_add_cert(store, x509); |
|
1043 |
2 |
X509_free(x509); |
|
1044 |
} |
||
1045 |
|||
1046 |
2 |
unsigned long err = ERR_peek_error(); // NOLINT(runtime/int) |
|
1047 |
// Ignore error if its EOF/no start line found. |
||
1048 |
✓✗✓✗ |
4 |
if (ERR_GET_LIB(err) == ERR_LIB_PEM && |
1049 |
2 |
ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { |
|
1050 |
2 |
return 0; |
|
1051 |
} |
||
1052 |
|||
1053 |
3 |
return err; |
|
1054 |
} |
||
1055 |
|||
1056 |
|||
1057 |
3 |
void UseExtraCaCerts(const std::string& file) { |
|
1058 |
ClearErrorOnReturn clear_error_on_return; |
||
1059 |
|||
1060 |
✓✗ | 3 |
if (root_cert_store == nullptr) { |
1061 |
3 |
root_cert_store = NewRootCertStore(); |
|
1062 |
|||
1063 |
✓✗ | 3 |
if (!file.empty()) { |
1064 |
unsigned long err = AddCertsFromFile( // NOLINT(runtime/int) |
||
1065 |
root_cert_store, |
||
1066 |
3 |
file.c_str()); |
|
1067 |
✓✓ | 3 |
if (err) { |
1068 |
fprintf(stderr, |
||
1069 |
"Warning: Ignoring extra certs from `%s`, load failed: %s\n", |
||
1070 |
file.c_str(), |
||
1071 |
1 |
ERR_error_string(err, nullptr)); |
|
1072 |
} else { |
||
1073 |
2 |
extra_root_certs_loaded = true; |
|
1074 |
} |
||
1075 |
} |
||
1076 |
3 |
} |
|
1077 |
3 |
} |
|
1078 |
|||
1079 |
|||
1080 |
static void IsExtraRootCertsFileLoaded( |
||
1081 |
const FunctionCallbackInfo<Value>& args) { |
||
1082 |
return args.GetReturnValue().Set(extra_root_certs_loaded); |
||
1083 |
} |
||
1084 |
|||
1085 |
|||
1086 |
1768 |
void SecureContext::AddRootCerts(const FunctionCallbackInfo<Value>& args) { |
|
1087 |
SecureContext* sc; |
||
1088 |
✗✓ | 3536 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1089 |
ClearErrorOnReturn clear_error_on_return; |
||
1090 |
|||
1091 |
✓✓ | 1768 |
if (root_cert_store == nullptr) { |
1092 |
295 |
root_cert_store = NewRootCertStore(); |
|
1093 |
} |
||
1094 |
|||
1095 |
// Increment reference count so global store is not deleted along with CTX. |
||
1096 |
1768 |
X509_STORE_up_ref(root_cert_store); |
|
1097 |
1768 |
SSL_CTX_set_cert_store(sc->ctx_.get(), root_cert_store); |
|
1098 |
} |
||
1099 |
|||
1100 |
|||
1101 |
2221 |
void SecureContext::SetCipherSuites(const FunctionCallbackInfo<Value>& args) { |
|
1102 |
// BoringSSL doesn't allow API config of TLS1.3 cipher suites. |
||
1103 |
#ifndef OPENSSL_IS_BORINGSSL |
||
1104 |
SecureContext* sc; |
||
1105 |
✗✓ | 2222 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1106 |
2221 |
Environment* env = sc->env(); |
|
1107 |
ClearErrorOnReturn clear_error_on_return; |
||
1108 |
|||
1109 |
✗✓ | 2221 |
CHECK_EQ(args.Length(), 1); |
1110 |
✗✓ | 6663 |
CHECK(args[0]->IsString()); |
1111 |
|||
1112 |
✓✓ | 4441 |
const node::Utf8Value ciphers(args.GetIsolate(), args[0]); |
1113 |
✓✓ | 2221 |
if (!SSL_CTX_set_ciphersuites(sc->ctx_.get(), *ciphers)) { |
1114 |
1 |
unsigned long err = ERR_get_error(); // NOLINT(runtime/int) |
|
1115 |
✗✓ | 1 |
if (!err) { |
1116 |
// This would be an OpenSSL bug if it happened. |
||
1117 |
return env->ThrowError("Failed to set ciphers"); |
||
1118 |
} |
||
1119 |
✓✓ | 1 |
return ThrowCryptoError(env, err); |
1120 |
2220 |
} |
|
1121 |
#endif |
||
1122 |
} |
||
1123 |
|||
1124 |
|||
1125 |
2223 |
void SecureContext::SetCiphers(const FunctionCallbackInfo<Value>& args) { |
|
1126 |
SecureContext* sc; |
||
1127 |
✗✓ | 2238 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1128 |
2223 |
Environment* env = sc->env(); |
|
1129 |
ClearErrorOnReturn clear_error_on_return; |
||
1130 |
|||
1131 |
✗✓ | 2223 |
CHECK_EQ(args.Length(), 1); |
1132 |
✗✓ | 6669 |
CHECK(args[0]->IsString()); |
1133 |
|||
1134 |
✓✓ | 4431 |
const node::Utf8Value ciphers(args.GetIsolate(), args[0]); |
1135 |
✓✓ | 2223 |
if (!SSL_CTX_set_cipher_list(sc->ctx_.get(), *ciphers)) { |
1136 |
15 |
unsigned long err = ERR_get_error(); // NOLINT(runtime/int) |
|
1137 |
✗✓ | 15 |
if (!err) { |
1138 |
// This would be an OpenSSL bug if it happened. |
||
1139 |
return env->ThrowError("Failed to set ciphers"); |
||
1140 |
} |
||
1141 |
|||
1142 |
✓✓✓✗ ✓✓ |
15 |
if (strlen(*ciphers) == 0 && ERR_GET_REASON(err) == SSL_R_NO_CIPHER_MATCH) { |
1143 |
// TLS1.2 ciphers were deliberately cleared, so don't consider |
||
1144 |
// SSL_R_NO_CIPHER_MATCH to be an error (this is how _set_cipher_suites() |
||
1145 |
// works). If the user actually sets a value (like "no-such-cipher"), then |
||
1146 |
// that's actually an error. |
||
1147 |
11 |
return; |
|
1148 |
} |
||
1149 |
✓✓ | 4 |
return ThrowCryptoError(env, err); |
1150 |
2208 |
} |
|
1151 |
} |
||
1152 |
|||
1153 |
|||
1154 |
2216 |
void SecureContext::SetECDHCurve(const FunctionCallbackInfo<Value>& args) { |
|
1155 |
SecureContext* sc; |
||
1156 |
✗✓ | 4425 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1157 |
2216 |
Environment* env = sc->env(); |
|
1158 |
|||
1159 |
✗✓ | 2216 |
if (args.Length() != 1) |
1160 |
return THROW_ERR_MISSING_ARGS(env, "ECDH curve name argument is mandatory"); |
||
1161 |
|||
1162 |
✓✓ | 6648 |
THROW_AND_RETURN_IF_NOT_STRING(env, args[0], "ECDH curve name"); |
1163 |
|||
1164 |
2215 |
node::Utf8Value curve(env->isolate(), args[0]); |
|
1165 |
|||
1166 |
✓✓ | 2215 |
if (strcmp(*curve, "auto") == 0) |
1167 |
2205 |
return; |
|
1168 |
|||
1169 |
✓✓ | 10 |
if (!SSL_CTX_set1_curves_list(sc->ctx_.get(), *curve)) |
1170 |
✓✓ | 3 |
return env->ThrowError("Failed to set ECDH curve"); |
1171 |
} |
||
1172 |
|||
1173 |
|||
1174 |
10 |
void SecureContext::SetDHParam(const FunctionCallbackInfo<Value>& args) { |
|
1175 |
SecureContext* sc; |
||
1176 |
✗✓ | 13 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.This()); |
1177 |
10 |
Environment* env = sc->env(); |
|
1178 |
ClearErrorOnReturn clear_error_on_return; |
||
1179 |
|||
1180 |
// Auto DH is not supported in openssl 1.0.1, so dhparam needs |
||
1181 |
// to be specified explicitly |
||
1182 |
✗✓ | 10 |
if (args.Length() != 1) |
1183 |
return THROW_ERR_MISSING_ARGS(env, "DH argument is mandatory"); |
||
1184 |
|||
1185 |
✓✓ | 17 |
DHPointer dh; |
1186 |
{ |
||
1187 |
10 |
BIOPointer bio(LoadBIO(env, args[0])); |
|
1188 |
✗✓ | 10 |
if (!bio) |
1189 |
return; |
||
1190 |
|||
1191 |
✓✗ | 10 |
dh.reset(PEM_read_bio_DHparams(bio.get(), nullptr, nullptr, nullptr)); |
1192 |
} |
||
1193 |
|||
1194 |
// Invalid dhparam is silently discarded and DHE is no longer used. |
||
1195 |
✓✓ | 10 |
if (!dh) |
1196 |
1 |
return; |
|
1197 |
|||
1198 |
const BIGNUM* p; |
||
1199 |
9 |
DH_get0_pqg(dh.get(), &p, nullptr, nullptr); |
|
1200 |
9 |
const int size = BN_num_bits(p); |
|
1201 |
✓✓ | 9 |
if (size < 1024) { |
1202 |
return THROW_ERR_INVALID_ARG_VALUE( |
||
1203 |
2 |
env, "DH parameter is less than 1024 bits"); |
|
1204 |
✓✓ | 7 |
} else if (size < 2048) { |
1205 |
args.GetReturnValue().Set(FIXED_ONE_BYTE_STRING( |
||
1206 |
9 |
env->isolate(), "DH parameter is less than 2048 bits")); |
|
1207 |
} |
||
1208 |
|||
1209 |
7 |
SSL_CTX_set_options(sc->ctx_.get(), SSL_OP_SINGLE_DH_USE); |
|
1210 |
7 |
int r = SSL_CTX_set_tmp_dh(sc->ctx_.get(), dh.get()); |
|
1211 |
|||
1212 |
✗✓ | 7 |
if (!r) |
1213 |
✓✓ | 7 |
return env->ThrowTypeError("Error setting temp DH parameter"); |
1214 |
} |
||
1215 |
|||
1216 |
|||
1217 |
11 |
void SecureContext::SetMinProto(const FunctionCallbackInfo<Value>& args) { |
|
1218 |
SecureContext* sc; |
||
1219 |
✗✓ | 22 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1220 |
|||
1221 |
✗✓ | 11 |
CHECK_EQ(args.Length(), 1); |
1222 |
✗✓ | 22 |
CHECK(args[0]->IsInt32()); |
1223 |
|||
1224 |
33 |
int version = args[0].As<Int32>()->Value(); |
|
1225 |
|||
1226 |
✗✓ | 11 |
CHECK(SSL_CTX_set_min_proto_version(sc->ctx_.get(), version)); |
1227 |
} |
||
1228 |
|||
1229 |
|||
1230 |
45 |
void SecureContext::SetMaxProto(const FunctionCallbackInfo<Value>& args) { |
|
1231 |
SecureContext* sc; |
||
1232 |
✗✓ | 90 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1233 |
|||
1234 |
✗✓ | 45 |
CHECK_EQ(args.Length(), 1); |
1235 |
✗✓ | 90 |
CHECK(args[0]->IsInt32()); |
1236 |
|||
1237 |
135 |
int version = args[0].As<Int32>()->Value(); |
|
1238 |
|||
1239 |
✗✓ | 45 |
CHECK(SSL_CTX_set_max_proto_version(sc->ctx_.get(), version)); |
1240 |
} |
||
1241 |
|||
1242 |
|||
1243 |
56 |
void SecureContext::GetMinProto(const FunctionCallbackInfo<Value>& args) { |
|
1244 |
SecureContext* sc; |
||
1245 |
✗✓ | 112 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1246 |
|||
1247 |
✗✓ | 56 |
CHECK_EQ(args.Length(), 0); |
1248 |
|||
1249 |
long version = // NOLINT(runtime/int) |
||
1250 |
56 |
SSL_CTX_get_min_proto_version(sc->ctx_.get()); |
|
1251 |
168 |
args.GetReturnValue().Set(static_cast<uint32_t>(version)); |
|
1252 |
} |
||
1253 |
|||
1254 |
|||
1255 |
75 |
void SecureContext::GetMaxProto(const FunctionCallbackInfo<Value>& args) { |
|
1256 |
SecureContext* sc; |
||
1257 |
✗✓ | 150 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1258 |
|||
1259 |
✗✓ | 75 |
CHECK_EQ(args.Length(), 0); |
1260 |
|||
1261 |
long version = // NOLINT(runtime/int) |
||
1262 |
75 |
SSL_CTX_get_max_proto_version(sc->ctx_.get()); |
|
1263 |
225 |
args.GetReturnValue().Set(static_cast<uint32_t>(version)); |
|
1264 |
} |
||
1265 |
|||
1266 |
|||
1267 |
808 |
void SecureContext::SetOptions(const FunctionCallbackInfo<Value>& args) { |
|
1268 |
SecureContext* sc; |
||
1269 |
✗✓ | 808 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1270 |
int64_t val; |
||
1271 |
|||
1272 |
✓✗✗✓ ✗✓ |
4040 |
if (args.Length() != 1 || |
1273 |
✓✗✗✓ |
4848 |
!args[0]->IntegerValue(args.GetIsolate()->GetCurrentContext()).To(&val)) { |
1274 |
return THROW_ERR_INVALID_ARG_TYPE( |
||
1275 |
sc->env(), "Options must be an integer value"); |
||
1276 |
} |
||
1277 |
|||
1278 |
SSL_CTX_set_options(sc->ctx_.get(), |
||
1279 |
808 |
static_cast<long>(val)); // NOLINT(runtime/int) |
|
1280 |
} |
||
1281 |
|||
1282 |
|||
1283 |
737 |
void SecureContext::SetSessionIdContext( |
|
1284 |
const FunctionCallbackInfo<Value>& args) { |
||
1285 |
SecureContext* sc; |
||
1286 |
✗✓ | 1474 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1287 |
737 |
Environment* env = sc->env(); |
|
1288 |
|||
1289 |
✗✓ | 737 |
if (args.Length() != 1) { |
1290 |
return THROW_ERR_MISSING_ARGS( |
||
1291 |
env, "Session ID context argument is mandatory"); |
||
1292 |
} |
||
1293 |
|||
1294 |
✗✓ | 2211 |
THROW_AND_RETURN_IF_NOT_STRING(env, args[0], "Session ID context"); |
1295 |
|||
1296 |
737 |
const node::Utf8Value sessionIdContext(args.GetIsolate(), args[0]); |
|
1297 |
const unsigned char* sid_ctx = |
||
1298 |
737 |
reinterpret_cast<const unsigned char*>(*sessionIdContext); |
|
1299 |
737 |
unsigned int sid_ctx_len = sessionIdContext.length(); |
|
1300 |
|||
1301 |
737 |
int r = SSL_CTX_set_session_id_context(sc->ctx_.get(), sid_ctx, sid_ctx_len); |
|
1302 |
✓✗ | 737 |
if (r == 1) |
1303 |
737 |
return; |
|
1304 |
|||
1305 |
BUF_MEM* mem; |
||
1306 |
Local<String> message; |
||
1307 |
|||
1308 |
BIOPointer bio(BIO_new(BIO_s_mem())); |
||
1309 |
if (!bio) { |
||
1310 |
message = FIXED_ONE_BYTE_STRING(args.GetIsolate(), |
||
1311 |
"SSL_CTX_set_session_id_context error"); |
||
1312 |
} else { |
||
1313 |
ERR_print_errors(bio.get()); |
||
1314 |
BIO_get_mem_ptr(bio.get(), &mem); |
||
1315 |
message = OneByteString(args.GetIsolate(), mem->data, mem->length); |
||
1316 |
} |
||
1317 |
|||
1318 |
args.GetIsolate()->ThrowException(Exception::TypeError(message)); |
||
1319 |
} |
||
1320 |
|||
1321 |
|||
1322 |
2 |
void SecureContext::SetSessionTimeout(const FunctionCallbackInfo<Value>& args) { |
|
1323 |
SecureContext* sc; |
||
1324 |
✗✓ | 3 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1325 |
|||
1326 |
✓✗✓✓ ✓✗✓✓ |
8 |
if (args.Length() != 1 || !args[0]->IsInt32()) { |
1327 |
return THROW_ERR_INVALID_ARG_TYPE( |
||
1328 |
1 |
sc->env(), "Session timeout must be a 32-bit integer"); |
|
1329 |
} |
||
1330 |
|||
1331 |
3 |
int32_t sessionTimeout = args[0].As<Int32>()->Value(); |
|
1332 |
1 |
SSL_CTX_set_timeout(sc->ctx_.get(), sessionTimeout); |
|
1333 |
} |
||
1334 |
|||
1335 |
|||
1336 |
1315 |
void SecureContext::Close(const FunctionCallbackInfo<Value>& args) { |
|
1337 |
SecureContext* sc; |
||
1338 |
✗✓ | 2630 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1339 |
1315 |
sc->Reset(); |
|
1340 |
} |
||
1341 |
|||
1342 |
|||
1343 |
// Takes .pfx or .p12 and password in string or buffer format |
||
1344 |
18 |
void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) { |
|
1345 |
18 |
Environment* env = Environment::GetCurrent(args); |
|
1346 |
|||
1347 |
18 |
std::vector<char> pass; |
|
1348 |
18 |
bool ret = false; |
|
1349 |
|||
1350 |
SecureContext* sc; |
||
1351 |
✗✓ | 18 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
1352 |
✓✓ | 12 |
ClearErrorOnReturn clear_error_on_return; |
1353 |
|||
1354 |
✗✓ | 18 |
if (args.Length() < 1) { |
1355 |
return THROW_ERR_MISSING_ARGS(env, "PFX certificate argument is mandatory"); |
||
1356 |
} |
||
1357 |
|||
1358 |
✓✓ | 30 |
BIOPointer in(LoadBIO(env, args[0])); |
1359 |
✗✓ | 18 |
if (!in) |
1360 |
return env->ThrowError("Unable to load BIO"); |
||
1361 |
|||
1362 |
✓✓ | 18 |
if (args.Length() >= 2) { |
1363 |
✗✓ | 15 |
THROW_AND_RETURN_IF_NOT_BUFFER(env, args[1], "Pass phrase"); |
1364 |
30 |
Local<ArrayBufferView> abv = args[1].As<ArrayBufferView>(); |
|
1365 |
15 |
size_t passlen = abv->ByteLength(); |
|
1366 |
15 |
pass.resize(passlen + 1); |
|
1367 |
30 |
abv->CopyContents(pass.data(), passlen); |
|
1368 |
15 |
pass[passlen] = '\0'; |
|
1369 |
} |
||
1370 |
|||
1371 |
// Free previous certs |
||
1372 |
18 |
sc->issuer_.reset(); |
|
1373 |
18 |
sc->cert_.reset(); |
|
1374 |
|||
1375 |
18 |
X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_.get()); |
|
1376 |
|||
1377 |
✓✓ | 30 |
DeleteFnPtr<PKCS12, PKCS12_free> p12; |
1378 |
✓✓ | 30 |
EVPKeyPointer pkey; |
1379 |
✓✓ | 30 |
X509Pointer cert; |
1380 |
✓✓ | 30 |
StackOfX509 extra_certs; |
1381 |
|||
1382 |
18 |
PKCS12* p12_ptr = nullptr; |
|
1383 |
18 |
EVP_PKEY* pkey_ptr = nullptr; |
|
1384 |
18 |
X509* cert_ptr = nullptr; |
|
1385 |
18 |
STACK_OF(X509)* extra_certs_ptr = nullptr; |
|
1386 |
✓✓ | 36 |
if (d2i_PKCS12_bio(in.get(), &p12_ptr) && |
1387 |
✓✓ | 32 |
(p12.reset(p12_ptr), true) && // Move ownership to the smart pointer. |
1388 |
16 |
PKCS12_parse(p12.get(), pass.data(), |
|
1389 |
&pkey_ptr, |
||
1390 |
&cert_ptr, |
||
1391 |
16 |
&extra_certs_ptr) && |
|
1392 |
12 |
(pkey.reset(pkey_ptr), cert.reset(cert_ptr), |
|
1393 |
✓✗ | 24 |
extra_certs.reset(extra_certs_ptr), true) && // Move ownership. |
1394 |
SSL_CTX_use_certificate_chain(sc->ctx_.get(), |
||
1395 |
12 |
std::move(cert), |
|
1396 |
extra_certs.get(), |
||
1397 |
&sc->cert_, |
||
1398 |
✓✓✓✗ |
54 |
&sc->issuer_) && |
1399 |
12 |
SSL_CTX_use_PrivateKey(sc->ctx_.get(), pkey.get())) { |
|
1400 |
// Add CA certs too |
||
1401 |
✓✓ | 21 |
for (int i = 0; i < sk_X509_num(extra_certs.get()); i++) { |
1402 |
9 |
X509* ca = sk_X509_value(extra_certs.get(), i); |
|
1403 |
|||
1404 |
✓✓ | 9 |
if (cert_store == root_cert_store) { |
1405 |
6 |
cert_store = NewRootCertStore(); |
|
1406 |
6 |
SSL_CTX_set_cert_store(sc->ctx_.get(), cert_store); |
|
1407 |
} |
||
1408 |
9 |
X509_STORE_add_cert(cert_store, ca); |
|
1409 |
9 |
SSL_CTX_add_client_CA(sc->ctx_.get(), ca); |
|
1410 |
} |
||
1411 |
12 |
ret = true; |
|
1412 |
} |
||
1413 |
|||
1414 |
✓✓ | 18 |
if (!ret) { |
1415 |
6 |
unsigned long err = ERR_get_error(); // NOLINT(runtime/int) |
|
1416 |
6 |
const char* str = ERR_reason_error_string(err); |
|
1417 |
✓✓ | 6 |
return env->ThrowError(str); |
1418 |
12 |
} |
|
1419 |
} |
||
1420 |
|||
1421 |
|||
1422 |
#ifndef OPENSSL_NO_ENGINE |
||
1423 |
// Helper for the smart pointer. |
||
1424 |
void ENGINE_free_fn(ENGINE* engine) { ENGINE_free(engine); } |
||
1425 |
|||
1426 |
void SecureContext::SetClientCertEngine( |
||
1427 |
const FunctionCallbackInfo<Value>& args) { |
||
1428 |
Environment* env = Environment::GetCurrent(args); |
||
1429 |
CHECK_EQ(args.Length(), 1); |
||
1430 |
CHECK(args[0]->IsString()); |
||
1431 |
|||
1432 |
SecureContext* sc; |
||
1433 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
||
1434 |
|||
1435 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
||
1436 |
|||
1437 |
// SSL_CTX_set_client_cert_engine does not itself support multiple |
||
1438 |
// calls by cleaning up before overwriting the client_cert_engine |
||
1439 |
// internal context variable. |
||
1440 |
// Instead of trying to fix up this problem we in turn also do not |
||
1441 |
// support multiple calls to SetClientCertEngine. |
||
1442 |
if (sc->client_cert_engine_provided_) { |
||
1443 |
return env->ThrowError( |
||
1444 |
"Multiple calls to SetClientCertEngine are not allowed"); |
||
1445 |
} |
||
1446 |
|||
1447 |
const node::Utf8Value engine_id(env->isolate(), args[0]); |
||
1448 |
char errmsg[1024]; |
||
1449 |
DeleteFnPtr<ENGINE, ENGINE_free_fn> engine( |
||
1450 |
LoadEngineById(*engine_id, &errmsg)); |
||
1451 |
|||
1452 |
if (!engine) |
||
1453 |
return env->ThrowError(errmsg); |
||
1454 |
|||
1455 |
// Note that this takes another reference to `engine`. |
||
1456 |
int r = SSL_CTX_set_client_cert_engine(sc->ctx_.get(), engine.get()); |
||
1457 |
if (r == 0) |
||
1458 |
return ThrowCryptoError(env, ERR_get_error()); |
||
1459 |
sc->client_cert_engine_provided_ = true; |
||
1460 |
} |
||
1461 |
#endif // !OPENSSL_NO_ENGINE |
||
1462 |
|||
1463 |
|||
1464 |
10 |
void SecureContext::GetTicketKeys(const FunctionCallbackInfo<Value>& args) { |
|
1465 |
#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_get_tlsext_ticket_keys) |
||
1466 |
|||
1467 |
SecureContext* wrap; |
||
1468 |
✗✓ | 20 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
1469 |
|||
1470 |
20 |
Local<Object> buff = Buffer::New(wrap->env(), 48).ToLocalChecked(); |
|
1471 |
10 |
memcpy(Buffer::Data(buff), wrap->ticket_key_name_, 16); |
|
1472 |
10 |
memcpy(Buffer::Data(buff) + 16, wrap->ticket_key_hmac_, 16); |
|
1473 |
10 |
memcpy(Buffer::Data(buff) + 32, wrap->ticket_key_aes_, 16); |
|
1474 |
|||
1475 |
20 |
args.GetReturnValue().Set(buff); |
|
1476 |
#endif // !def(OPENSSL_NO_TLSEXT) && def(SSL_CTX_get_tlsext_ticket_keys) |
||
1477 |
} |
||
1478 |
|||
1479 |
|||
1480 |
25 |
void SecureContext::SetTicketKeys(const FunctionCallbackInfo<Value>& args) { |
|
1481 |
#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_get_tlsext_ticket_keys) |
||
1482 |
SecureContext* wrap; |
||
1483 |
✗✓ | 27 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
1484 |
25 |
Environment* env = wrap->env(); |
|
1485 |
|||
1486 |
// TODO(@sam-github) Move type and len check to js, and CHECK() in C++. |
||
1487 |
✗✓ | 25 |
if (args.Length() < 1) { |
1488 |
return THROW_ERR_MISSING_ARGS(env, "Ticket keys argument is mandatory"); |
||
1489 |
} |
||
1490 |
|||
1491 |
✓✓ | 25 |
THROW_AND_RETURN_IF_NOT_BUFFER(env, args[0], "Ticket keys"); |
1492 |
48 |
ArrayBufferViewContents<char> buf(args[0].As<ArrayBufferView>()); |
|
1493 |
|||
1494 |
✓✓ | 24 |
if (buf.length() != 48) { |
1495 |
return THROW_ERR_INVALID_ARG_VALUE( |
||
1496 |
1 |
env, "Ticket keys length must be 48 bytes"); |
|
1497 |
} |
||
1498 |
|||
1499 |
23 |
memcpy(wrap->ticket_key_name_, buf.data(), 16); |
|
1500 |
23 |
memcpy(wrap->ticket_key_hmac_, buf.data() + 16, 16); |
|
1501 |
23 |
memcpy(wrap->ticket_key_aes_, buf.data() + 32, 16); |
|
1502 |
|||
1503 |
46 |
args.GetReturnValue().Set(true); |
|
1504 |
#endif // !def(OPENSSL_NO_TLSEXT) && def(SSL_CTX_get_tlsext_ticket_keys) |
||
1505 |
} |
||
1506 |
|||
1507 |
|||
1508 |
1346 |
void SecureContext::SetFreeListLength(const FunctionCallbackInfo<Value>& args) { |
|
1509 |
1346 |
} |
|
1510 |
|||
1511 |
|||
1512 |
// Currently, EnableTicketKeyCallback and TicketKeyCallback are only present for |
||
1513 |
// the regression test in test/parallel/test-https-resume-after-renew.js. |
||
1514 |
1 |
void SecureContext::EnableTicketKeyCallback( |
|
1515 |
const FunctionCallbackInfo<Value>& args) { |
||
1516 |
SecureContext* wrap; |
||
1517 |
✗✓ | 2 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
1518 |
|||
1519 |
1 |
SSL_CTX_set_tlsext_ticket_key_cb(wrap->ctx_.get(), TicketKeyCallback); |
|
1520 |
} |
||
1521 |
|||
1522 |
|||
1523 |
4 |
int SecureContext::TicketKeyCallback(SSL* ssl, |
|
1524 |
unsigned char* name, |
||
1525 |
unsigned char* iv, |
||
1526 |
EVP_CIPHER_CTX* ectx, |
||
1527 |
HMAC_CTX* hctx, |
||
1528 |
int enc) { |
||
1529 |
static const int kTicketPartSize = 16; |
||
1530 |
|||
1531 |
SecureContext* sc = static_cast<SecureContext*>( |
||
1532 |
4 |
SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl))); |
|
1533 |
|||
1534 |
4 |
Environment* env = sc->env(); |
|
1535 |
4 |
HandleScope handle_scope(env->isolate()); |
|
1536 |
4 |
Context::Scope context_scope(env->context()); |
|
1537 |
|||
1538 |
Local<Value> argv[] = { |
||
1539 |
Buffer::Copy(env, |
||
1540 |
reinterpret_cast<char*>(name), |
||
1541 |
kTicketPartSize).ToLocalChecked(), |
||
1542 |
Buffer::Copy(env, |
||
1543 |
reinterpret_cast<char*>(iv), |
||
1544 |
kTicketPartSize).ToLocalChecked(), |
||
1545 |
Boolean::New(env->isolate(), enc != 0) |
||
1546 |
16 |
}; |
|
1547 |
|||
1548 |
Local<Value> ret = node::MakeCallback(env->isolate(), |
||
1549 |
sc->object(), |
||
1550 |
env->ticketkeycallback_string(), |
||
1551 |
4 |
arraysize(argv), |
|
1552 |
argv, |
||
1553 |
12 |
{0, 0}).ToLocalChecked(); |
|
1554 |
4 |
Local<Array> arr = ret.As<Array>(); |
|
1555 |
|||
1556 |
int r = |
||
1557 |
4 |
arr->Get(env->context(), |
|
1558 |
12 |
kTicketKeyReturnIndex).ToLocalChecked() |
|
1559 |
16 |
->Int32Value(env->context()).FromJust(); |
|
1560 |
✗✓ | 4 |
if (r < 0) |
1561 |
return r; |
||
1562 |
|||
1563 |
4 |
Local<Value> hmac = arr->Get(env->context(), |
|
1564 |
12 |
kTicketKeyHMACIndex).ToLocalChecked(); |
|
1565 |
4 |
Local<Value> aes = arr->Get(env->context(), |
|
1566 |
12 |
kTicketKeyAESIndex).ToLocalChecked(); |
|
1567 |
✗✓ | 4 |
if (Buffer::Length(aes) != kTicketPartSize) |
1568 |
return -1; |
||
1569 |
|||
1570 |
✓✓ | 4 |
if (enc) { |
1571 |
3 |
Local<Value> name_val = arr->Get(env->context(), |
|
1572 |
9 |
kTicketKeyNameIndex).ToLocalChecked(); |
|
1573 |
3 |
Local<Value> iv_val = arr->Get(env->context(), |
|
1574 |
9 |
kTicketKeyIVIndex).ToLocalChecked(); |
|
1575 |
|||
1576 |
✓✗✗✓ ✗✓ |
6 |
if (Buffer::Length(name_val) != kTicketPartSize || |
1577 |
3 |
Buffer::Length(iv_val) != kTicketPartSize) { |
|
1578 |
return -1; |
||
1579 |
} |
||
1580 |
|||
1581 |
6 |
name_val.As<ArrayBufferView>()->CopyContents(name, kTicketPartSize); |
|
1582 |
6 |
iv_val.As<ArrayBufferView>()->CopyContents(iv, kTicketPartSize); |
|
1583 |
} |
||
1584 |
|||
1585 |
4 |
ArrayBufferViewContents<unsigned char> hmac_buf(hmac); |
|
1586 |
HMAC_Init_ex(hctx, |
||
1587 |
4 |
hmac_buf.data(), |
|
1588 |
4 |
hmac_buf.length(), |
|
1589 |
EVP_sha256(), |
||
1590 |
12 |
nullptr); |
|
1591 |
|||
1592 |
4 |
ArrayBufferViewContents<unsigned char> aes_key(aes.As<ArrayBufferView>()); |
|
1593 |
✓✓ | 4 |
if (enc) { |
1594 |
EVP_EncryptInit_ex(ectx, |
||
1595 |
EVP_aes_128_cbc(), |
||
1596 |
nullptr, |
||
1597 |
aes_key.data(), |
||
1598 |
3 |
iv); |
|
1599 |
} else { |
||
1600 |
EVP_DecryptInit_ex(ectx, |
||
1601 |
EVP_aes_128_cbc(), |
||
1602 |
nullptr, |
||
1603 |
aes_key.data(), |
||
1604 |
1 |
iv); |
|
1605 |
} |
||
1606 |
|||
1607 |
8 |
return r; |
|
1608 |
} |
||
1609 |
|||
1610 |
|||
1611 |
1152 |
int SecureContext::TicketCompatibilityCallback(SSL* ssl, |
|
1612 |
unsigned char* name, |
||
1613 |
unsigned char* iv, |
||
1614 |
EVP_CIPHER_CTX* ectx, |
||
1615 |
HMAC_CTX* hctx, |
||
1616 |
int enc) { |
||
1617 |
SecureContext* sc = static_cast<SecureContext*>( |
||
1618 |
1152 |
SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl))); |
|
1619 |
|||
1620 |
✓✓ | 1152 |
if (enc) { |
1621 |
1099 |
memcpy(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_)); |
|
1622 |
✓✗✗✓ |
3297 |
if (RAND_bytes(iv, 16) <= 0 || |
1623 |
EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), nullptr, |
||
1624 |
✓✗✗✓ |
2198 |
sc->ticket_key_aes_, iv) <= 0 || |
1625 |
HMAC_Init_ex(hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_), |
||
1626 |
1099 |
EVP_sha256(), nullptr) <= 0) { |
|
1627 |
return -1; |
||
1628 |
} |
||
1629 |
1099 |
return 1; |
|
1630 |
} |
||
1631 |
|||
1632 |
✓✓ | 53 |
if (memcmp(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_)) != 0) { |
1633 |
// The ticket key name does not match. Discard the ticket. |
||
1634 |
12 |
return 0; |
|
1635 |
} |
||
1636 |
|||
1637 |
✗✓ | 41 |
if (EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), nullptr, sc->ticket_key_aes_, |
1638 |
✓✗✗✓ |
82 |
iv) <= 0 || |
1639 |
HMAC_Init_ex(hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_), |
||
1640 |
41 |
EVP_sha256(), nullptr) <= 0) { |
|
1641 |
return -1; |
||
1642 |
} |
||
1643 |
41 |
return 1; |
|
1644 |
} |
||
1645 |
|||
1646 |
|||
1647 |
2 |
void SecureContext::CtxGetter(const FunctionCallbackInfo<Value>& info) { |
|
1648 |
SecureContext* sc; |
||
1649 |
✗✓ | 4 |
ASSIGN_OR_RETURN_UNWRAP(&sc, info.This()); |
1650 |
4 |
Local<External> ext = External::New(info.GetIsolate(), sc->ctx_.get()); |
|
1651 |
4 |
info.GetReturnValue().Set(ext); |
|
1652 |
} |
||
1653 |
|||
1654 |
|||
1655 |
template <bool primary> |
||
1656 |
6 |
void SecureContext::GetCertificate(const FunctionCallbackInfo<Value>& args) { |
|
1657 |
SecureContext* wrap; |
||
1658 |
✗✓✗✓ |
6 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
1659 |
6 |
Environment* env = wrap->env(); |
|
1660 |
X509* cert; |
||
1661 |
|||
1662 |
if (primary) |
||
1663 |
3 |
cert = wrap->cert_.get(); |
|
1664 |
else |
||
1665 |
3 |
cert = wrap->issuer_.get(); |
|
1666 |
✗✓✗✓ |
6 |
if (cert == nullptr) |
1667 |
return args.GetReturnValue().SetNull(); |
||
1668 |
|||
1669 |
6 |
int size = i2d_X509(cert, nullptr); |
|
1670 |
12 |
Local<Object> buff = Buffer::New(env, size).ToLocalChecked(); |
|
1671 |
unsigned char* serialized = reinterpret_cast<unsigned char*>( |
||
1672 |
6 |
Buffer::Data(buff)); |
|
1673 |
6 |
i2d_X509(cert, &serialized); |
|
1674 |
|||
1675 |
12 |
args.GetReturnValue().Set(buff); |
|
1676 |
} |
||
1677 |
|||
1678 |
|||
1679 |
template <class Base> |
||
1680 |
551 |
void SSLWrap<Base>::AddMethods(Environment* env, Local<FunctionTemplate> t) { |
|
1681 |
551 |
HandleScope scope(env->isolate()); |
|
1682 |
|||
1683 |
551 |
env->SetProtoMethodNoSideEffect(t, "getPeerCertificate", GetPeerCertificate); |
|
1684 |
551 |
env->SetProtoMethodNoSideEffect(t, "getCertificate", GetCertificate); |
|
1685 |
551 |
env->SetProtoMethodNoSideEffect(t, "getFinished", GetFinished); |
|
1686 |
551 |
env->SetProtoMethodNoSideEffect(t, "getPeerFinished", GetPeerFinished); |
|
1687 |
551 |
env->SetProtoMethodNoSideEffect(t, "getSession", GetSession); |
|
1688 |
551 |
env->SetProtoMethod(t, "setSession", SetSession); |
|
1689 |
551 |
env->SetProtoMethod(t, "loadSession", LoadSession); |
|
1690 |
551 |
env->SetProtoMethodNoSideEffect(t, "isSessionReused", IsSessionReused); |
|
1691 |
551 |
env->SetProtoMethodNoSideEffect(t, "verifyError", VerifyError); |
|
1692 |
551 |
env->SetProtoMethodNoSideEffect(t, "getCipher", GetCipher); |
|
1693 |
551 |
env->SetProtoMethod(t, "endParser", EndParser); |
|
1694 |
551 |
env->SetProtoMethod(t, "certCbDone", CertCbDone); |
|
1695 |
551 |
env->SetProtoMethod(t, "renegotiate", Renegotiate); |
|
1696 |
551 |
env->SetProtoMethodNoSideEffect(t, "getTLSTicket", GetTLSTicket); |
|
1697 |
551 |
env->SetProtoMethod(t, "newSessionDone", NewSessionDone); |
|
1698 |
551 |
env->SetProtoMethod(t, "setOCSPResponse", SetOCSPResponse); |
|
1699 |
551 |
env->SetProtoMethod(t, "requestOCSP", RequestOCSP); |
|
1700 |
551 |
env->SetProtoMethodNoSideEffect(t, "getEphemeralKeyInfo", |
|
1701 |
GetEphemeralKeyInfo); |
||
1702 |
551 |
env->SetProtoMethodNoSideEffect(t, "getProtocol", GetProtocol); |
|
1703 |
|||
1704 |
#ifdef SSL_set_max_send_fragment |
||
1705 |
551 |
env->SetProtoMethod(t, "setMaxSendFragment", SetMaxSendFragment); |
|
1706 |
#endif // SSL_set_max_send_fragment |
||
1707 |
|||
1708 |
551 |
env->SetProtoMethodNoSideEffect(t, "getALPNNegotiatedProtocol", |
|
1709 |
GetALPNNegotiatedProto); |
||
1710 |
551 |
env->SetProtoMethod(t, "setALPNProtocols", SetALPNProtocols); |
|
1711 |
551 |
} |
|
1712 |
|||
1713 |
|||
1714 |
template <class Base> |
||
1715 |
12250 |
void SSLWrap<Base>::ConfigureSecureContext(SecureContext* sc) { |
|
1716 |
// OCSP stapling |
||
1717 |
12250 |
SSL_CTX_set_tlsext_status_cb(sc->ctx_.get(), TLSExtStatusCallback); |
|
1718 |
12250 |
SSL_CTX_set_tlsext_status_arg(sc->ctx_.get(), nullptr); |
|
1719 |
12250 |
} |
|
1720 |
|||
1721 |
|||
1722 |
template <class Base> |
||
1723 |
113 |
SSL_SESSION* SSLWrap<Base>::GetSessionCallback(SSL* s, |
|
1724 |
const unsigned char* key, |
||
1725 |
int len, |
||
1726 |
int* copy) { |
||
1727 |
113 |
Base* w = static_cast<Base*>(SSL_get_app_data(s)); |
|
1728 |
|||
1729 |
113 |
*copy = 0; |
|
1730 |
113 |
return w->next_sess_.release(); |
|
1731 |
} |
||
1732 |
|||
1733 |
|||
1734 |
template <class Base> |
||
1735 |
1663 |
int SSLWrap<Base>::NewSessionCallback(SSL* s, SSL_SESSION* sess) { |
|
1736 |
1663 |
Base* w = static_cast<Base*>(SSL_get_app_data(s)); |
|
1737 |
1663 |
Environment* env = w->ssl_env(); |
|
1738 |
1663 |
HandleScope handle_scope(env->isolate()); |
|
1739 |
1663 |
Context::Scope context_scope(env->context()); |
|
1740 |
|||
1741 |
✓✓ | 1663 |
if (!w->session_callbacks_) |
1742 |
1306 |
return 0; |
|
1743 |
|||
1744 |
// Check if session is small enough to be stored |
||
1745 |
357 |
int size = i2d_SSL_SESSION(sess, nullptr); |
|
1746 |
✗✓ | 357 |
if (size > SecureContext::kMaxSessionSize) |
1747 |
return 0; |
||
1748 |
|||
1749 |
// Serialize session |
||
1750 |
714 |
Local<Object> session = Buffer::New(env, size).ToLocalChecked(); |
|
1751 |
unsigned char* session_data = reinterpret_cast<unsigned char*>( |
||
1752 |
357 |
Buffer::Data(session)); |
|
1753 |
357 |
memset(session_data, 0, size); |
|
1754 |
357 |
i2d_SSL_SESSION(sess, &session_data); |
|
1755 |
|||
1756 |
unsigned int session_id_length; |
||
1757 |
const unsigned char* session_id_data = SSL_SESSION_get_id(sess, |
||
1758 |
357 |
&session_id_length); |
|
1759 |
Local<Object> session_id = Buffer::Copy( |
||
1760 |
env, |
||
1761 |
reinterpret_cast<const char*>(session_id_data), |
||
1762 |
714 |
session_id_length).ToLocalChecked(); |
|
1763 |
1071 |
Local<Value> argv[] = { session_id, session }; |
|
1764 |
// On servers, we pause the handshake until callback of 'newSession', which |
||
1765 |
// calls NewSessionDoneCb(). On clients, there is no callback to wait for. |
||
1766 |
✓✓ | 357 |
if (w->is_server()) |
1767 |
8 |
w->awaiting_new_session_ = true; |
|
1768 |
357 |
w->MakeCallback(env->onnewsession_string(), arraysize(argv), argv); |
|
1769 |
|||
1770 |
2020 |
return 0; |
|
1771 |
} |
||
1772 |
|||
1773 |
|||
1774 |
template <class Base> |
||
1775 |
10 |
void SSLWrap<Base>::KeylogCallback(const SSL* s, const char* line) { |
|
1776 |
10 |
Base* w = static_cast<Base*>(SSL_get_app_data(s)); |
|
1777 |
10 |
Environment* env = w->ssl_env(); |
|
1778 |
10 |
HandleScope handle_scope(env->isolate()); |
|
1779 |
10 |
Context::Scope context_scope(env->context()); |
|
1780 |
|||
1781 |
10 |
const size_t size = strlen(line); |
|
1782 |
20 |
Local<Value> line_bf = Buffer::Copy(env, line, 1 + size).ToLocalChecked(); |
|
1783 |
10 |
char* data = Buffer::Data(line_bf); |
|
1784 |
10 |
data[size] = '\n'; |
|
1785 |
20 |
w->MakeCallback(env->onkeylog_string(), 1, &line_bf); |
|
1786 |
10 |
} |
|
1787 |
|||
1788 |
|||
1789 |
template <class Base> |
||
1790 |
20 |
void SSLWrap<Base>::OnClientHello(void* arg, |
|
1791 |
const ClientHelloParser::ClientHello& hello) { |
||
1792 |
20 |
Base* w = static_cast<Base*>(arg); |
|
1793 |
20 |
Environment* env = w->ssl_env(); |
|
1794 |
20 |
HandleScope handle_scope(env->isolate()); |
|
1795 |
20 |
Local<Context> context = env->context(); |
|
1796 |
Context::Scope context_scope(context); |
||
1797 |
|||
1798 |
20 |
Local<Object> hello_obj = Object::New(env->isolate()); |
|
1799 |
Local<Object> buff = Buffer::Copy( |
||
1800 |
env, |
||
1801 |
20 |
reinterpret_cast<const char*>(hello.session_id()), |
|
1802 |
60 |
hello.session_size()).ToLocalChecked(); |
|
1803 |
60 |
hello_obj->Set(context, env->session_id_string(), buff).Check(); |
|
1804 |
✓✓ | 20 |
if (hello.servername() == nullptr) { |
1805 |
hello_obj->Set(context, |
||
1806 |
env->servername_string(), |
||
1807 |
8 |
String::Empty(env->isolate())).Check(); |
|
1808 |
} else { |
||
1809 |
Local<String> servername = OneByteString(env->isolate(), |
||
1810 |
hello.servername(), |
||
1811 |
18 |
hello.servername_size()); |
|
1812 |
54 |
hello_obj->Set(context, env->servername_string(), servername).Check(); |
|
1813 |
} |
||
1814 |
hello_obj->Set(context, |
||
1815 |
env->tls_ticket_string(), |
||
1816 |
80 |
Boolean::New(env->isolate(), hello.has_ticket())).Check(); |
|
1817 |
|||
1818 |
40 |
Local<Value> argv[] = { hello_obj }; |
|
1819 |
40 |
w->MakeCallback(env->onclienthello_string(), arraysize(argv), argv); |
|
1820 |
20 |
} |
|
1821 |
|||
1822 |
|||
1823 |
302 |
static bool SafeX509ExtPrint(BIO* out, X509_EXTENSION* ext) { |
|
1824 |
302 |
const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext); |
|
1825 |
|||
1826 |
✓✓ | 302 |
if (method != X509V3_EXT_get_nid(NID_subject_alt_name)) |
1827 |
226 |
return false; |
|
1828 |
|||
1829 |
76 |
GENERAL_NAMES* names = static_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(ext)); |
|
1830 |
✗✓ | 76 |
if (names == nullptr) |
1831 |
return false; |
||
1832 |
|||
1833 |
✓✓ | 519 |
for (int i = 0; i < sk_GENERAL_NAME_num(names); i++) { |
1834 |
443 |
GENERAL_NAME* gen = sk_GENERAL_NAME_value(names, i); |
|
1835 |
|||
1836 |
✓✓ | 443 |
if (i != 0) |
1837 |
367 |
BIO_write(out, ", ", 2); |
|
1838 |
|||
1839 |
✓✓ | 443 |
if (gen->type == GEN_DNS) { |
1840 |
440 |
ASN1_IA5STRING* name = gen->d.dNSName; |
|
1841 |
|||
1842 |
440 |
BIO_write(out, "DNS:", 4); |
|
1843 |
440 |
BIO_write(out, name->data, name->length); |
|
1844 |
} else { |
||
1845 |
STACK_OF(CONF_VALUE)* nval = i2v_GENERAL_NAME( |
||
1846 |
3 |
const_cast<X509V3_EXT_METHOD*>(method), gen, nullptr); |
|
1847 |
✗✓ | 3 |
if (nval == nullptr) |
1848 |
return false; |
||
1849 |
3 |
X509V3_EXT_val_prn(out, nval, 0, 0); |
|
1850 |
3 |
sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); |
|
1851 |
} |
||
1852 |
} |
||
1853 |
76 |
sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); |
|
1854 |
|||
1855 |
76 |
return true; |
|
1856 |
} |
||
1857 |
|||
1858 |
|||
1859 |
2712 |
static void AddFingerprintDigest(const unsigned char* md, |
|
1860 |
unsigned int md_size, |
||
1861 |
char (*fingerprint)[3 * EVP_MAX_MD_SIZE + 1]) { |
||
1862 |
unsigned int i; |
||
1863 |
2712 |
const char hex[] = "0123456789ABCDEF"; |
|
1864 |
|||
1865 |
✓✓ | 73224 |
for (i = 0; i < md_size; i++) { |
1866 |
70512 |
(*fingerprint)[3*i] = hex[(md[i] & 0xf0) >> 4]; |
|
1867 |
70512 |
(*fingerprint)[(3*i)+1] = hex[(md[i] & 0x0f)]; |
|
1868 |
70512 |
(*fingerprint)[(3*i)+2] = ':'; |
|
1869 |
} |
||
1870 |
|||
1871 |
✓✗ | 2712 |
if (md_size > 0) { |
1872 |
2712 |
(*fingerprint)[(3*(md_size-1))+2] = '\0'; |
|
1873 |
} else { |
||
1874 |
(*fingerprint)[0] = '\0'; |
||
1875 |
} |
||
1876 |
2712 |
} |
|
1877 |
|||
1878 |
|||
1879 |
96 |
static MaybeLocal<Object> ECPointToBuffer(Environment* env, |
|
1880 |
const EC_GROUP* group, |
||
1881 |
const EC_POINT* point, |
||
1882 |
point_conversion_form_t form, |
||
1883 |
const char** error) { |
||
1884 |
96 |
size_t len = EC_POINT_point2oct(group, point, form, nullptr, 0, nullptr); |
|
1885 |
✗✓ | 96 |
if (len == 0) { |
1886 |
if (error != nullptr) *error = "Failed to get public key length"; |
||
1887 |
return MaybeLocal<Object>(); |
||
1888 |
} |
||
1889 |
96 |
AllocatedBuffer buf = env->AllocateManaged(len); |
|
1890 |
len = EC_POINT_point2oct(group, |
||
1891 |
point, |
||
1892 |
form, |
||
1893 |
96 |
reinterpret_cast<unsigned char*>(buf.data()), |
|
1894 |
buf.size(), |
||
1895 |
192 |
nullptr); |
|
1896 |
✗✓ | 96 |
if (len == 0) { |
1897 |
if (error != nullptr) *error = "Failed to get public key"; |
||
1898 |
return MaybeLocal<Object>(); |
||
1899 |
} |
||
1900 |
96 |
return buf.ToBuffer(); |
|
1901 |
} |
||
1902 |
|||
1903 |
|||
1904 |
1356 |
static Local<Object> X509ToObject(Environment* env, X509* cert) { |
|
1905 |
1356 |
EscapableHandleScope scope(env->isolate()); |
|
1906 |
1356 |
Local<Context> context = env->context(); |
|
1907 |
1356 |
Local<Object> info = Object::New(env->isolate()); |
|
1908 |
|||
1909 |
2712 |
BIOPointer bio(BIO_new(BIO_s_mem())); |
|
1910 |
BUF_MEM* mem; |
||
1911 |
✓✗ | 1356 |
if (X509_NAME_print_ex(bio.get(), |
1912 |
1356 |
X509_get_subject_name(cert), |
|
1913 |
0, |
||
1914 |
1356 |
X509_NAME_FLAGS) > 0) { |
|
1915 |
1356 |
BIO_get_mem_ptr(bio.get(), &mem); |
|
1916 |
info->Set(context, env->subject_string(), |
||
1917 |
String::NewFromUtf8(env->isolate(), mem->data, |
||
1918 |
NewStringType::kNormal, |
||
1919 |
5424 |
mem->length).ToLocalChecked()).Check(); |
|
1920 |
} |
||
1921 |
1356 |
USE(BIO_reset(bio.get())); |
|
1922 |
|||
1923 |
1356 |
X509_NAME* issuer_name = X509_get_issuer_name(cert); |
|
1924 |
✓✗ | 1356 |
if (X509_NAME_print_ex(bio.get(), issuer_name, 0, X509_NAME_FLAGS) > 0) { |
1925 |
1356 |
BIO_get_mem_ptr(bio.get(), &mem); |
|
1926 |
info->Set(context, env->issuer_string(), |
||
1927 |
String::NewFromUtf8(env->isolate(), mem->data, |
||
1928 |
NewStringType::kNormal, |
||
1929 |
5424 |
mem->length).ToLocalChecked()).Check(); |
|
1930 |
} |
||
1931 |
1356 |
USE(BIO_reset(bio.get())); |
|
1932 |
|||
1933 |
1356 |
int nids[] = { NID_subject_alt_name, NID_info_access }; |
|
1934 |
Local<String> keys[] = { env->subjectaltname_string(), |
||
1935 |
1356 |
env->infoaccess_string() }; |
|
1936 |
✗✓ | 1356 |
CHECK_EQ(arraysize(nids), arraysize(keys)); |
1937 |
✓✓ | 4068 |
for (size_t i = 0; i < arraysize(nids); i++) { |
1938 |
2712 |
int index = X509_get_ext_by_NID(cert, nids[i], -1); |
|
1939 |
✓✓ | 2712 |
if (index < 0) |
1940 |
2410 |
continue; |
|
1941 |
|||
1942 |
302 |
X509_EXTENSION* ext = X509_get_ext(cert, index); |
|
1943 |
✗✓ | 302 |
CHECK_NOT_NULL(ext); |
1944 |
|||
1945 |
✓✓ | 302 |
if (!SafeX509ExtPrint(bio.get(), ext)) { |
1946 |
✗✓ | 226 |
CHECK_EQ(1, X509V3_EXT_print(bio.get(), ext, 0, 0)); |
1947 |
} |
||
1948 |
|||
1949 |
302 |
BIO_get_mem_ptr(bio.get(), &mem); |
|
1950 |
info->Set(context, keys[i], |
||
1951 |
String::NewFromUtf8(env->isolate(), mem->data, |
||
1952 |
NewStringType::kNormal, |
||
1953 |
906 |
mem->length).ToLocalChecked()).Check(); |
|
1954 |
|||
1955 |
302 |
USE(BIO_reset(bio.get())); |
|
1956 |
} |
||
1957 |
|||
1958 |
2712 |
EVPKeyPointer pkey(X509_get_pubkey(cert)); |
|
1959 |
2712 |
RSAPointer rsa; |
|
1960 |
2712 |
ECPointer ec; |
|
1961 |
✓✗ | 1356 |
if (pkey) { |
1962 |
✓✓✗ | 1356 |
switch (EVP_PKEY_id(pkey.get())) { |
1963 |
case EVP_PKEY_RSA: |
||
1964 |
1286 |
rsa.reset(EVP_PKEY_get1_RSA(pkey.get())); |
|
1965 |
1286 |
break; |
|
1966 |
case EVP_PKEY_EC: |
||
1967 |
70 |
ec.reset(EVP_PKEY_get1_EC_KEY(pkey.get())); |
|
1968 |
70 |
break; |
|
1969 |
} |
||
1970 |
} |
||
1971 |
|||
1972 |
✓✓ | 1356 |
if (rsa) { |
1973 |
const BIGNUM* n; |
||
1974 |
const BIGNUM* e; |
||
1975 |
1286 |
RSA_get0_key(rsa.get(), &n, &e, nullptr); |
|
1976 |
1286 |
BN_print(bio.get(), n); |
|
1977 |
1286 |
BIO_get_mem_ptr(bio.get(), &mem); |
|
1978 |
info->Set(context, env->modulus_string(), |
||
1979 |
String::NewFromUtf8(env->isolate(), mem->data, |
||
1980 |
NewStringType::kNormal, |
||
1981 |
5144 |
mem->length).ToLocalChecked()).Check(); |
|
1982 |
1286 |
USE(BIO_reset(bio.get())); |
|
1983 |
|||
1984 |
1286 |
int bits = BN_num_bits(n); |
|
1985 |
info->Set(context, env->bits_string(), |
||
1986 |
5144 |
Integer::New(env->isolate(), bits)).Check(); |
|
1987 |
|||
1988 |
1286 |
uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(e)); |
|
1989 |
1286 |
uint32_t lo = static_cast<uint32_t>(exponent_word); |
|
1990 |
1286 |
uint32_t hi = static_cast<uint32_t>(exponent_word >> 32); |
|
1991 |
✓✗ | 1286 |
if (hi == 0) { |
1992 |
1286 |
BIO_printf(bio.get(), "0x%x", lo); |
|
1993 |
} else { |
||
1994 |
BIO_printf(bio.get(), "0x%x%08x", hi, lo); |
||
1995 |
} |
||
1996 |
1286 |
BIO_get_mem_ptr(bio.get(), &mem); |
|
1997 |
info->Set(context, env->exponent_string(), |
||
1998 |
String::NewFromUtf8(env->isolate(), mem->data, |
||
1999 |
NewStringType::kNormal, |
||
2000 |
5144 |
mem->length).ToLocalChecked()).Check(); |
|
2001 |
1286 |
USE(BIO_reset(bio.get())); |
|
2002 |
|||
2003 |
1286 |
int size = i2d_RSA_PUBKEY(rsa.get(), nullptr); |
|
2004 |
✗✓ | 1286 |
CHECK_GE(size, 0); |
2005 |
2572 |
Local<Object> pubbuff = Buffer::New(env, size).ToLocalChecked(); |
|
2006 |
unsigned char* pubserialized = |
||
2007 |
1286 |
reinterpret_cast<unsigned char*>(Buffer::Data(pubbuff)); |
|
2008 |
1286 |
i2d_RSA_PUBKEY(rsa.get(), &pubserialized); |
|
2009 |
5144 |
info->Set(env->context(), env->pubkey_string(), pubbuff).Check(); |
|
2010 |
✓✗ | 70 |
} else if (ec) { |
2011 |
70 |
const EC_GROUP* group = EC_KEY_get0_group(ec.get()); |
|
2012 |
✓✗ | 70 |
if (group != nullptr) { |
2013 |
70 |
int bits = EC_GROUP_order_bits(group); |
|
2014 |
✓✗ | 70 |
if (bits > 0) { |
2015 |
info->Set(context, env->bits_string(), |
||
2016 |
280 |
Integer::New(env->isolate(), bits)).Check(); |
|
2017 |
} |
||
2018 |
} |
||
2019 |
|||
2020 |
70 |
const EC_POINT* pubkey = EC_KEY_get0_public_key(ec.get()); |
|
2021 |
Local<Object> buf; |
||
2022 |
✓✗✓✗ ✓✗ |
280 |
if (pubkey != nullptr && |
2023 |
ECPointToBuffer( |
||
2024 |
70 |
env, group, pubkey, EC_KEY_get_conv_form(ec.get()), nullptr) |
|
2025 |
✗✓ | 280 |
.ToLocal(&buf)) { |
2026 |
210 |
info->Set(context, env->pubkey_string(), buf).Check(); |
|
2027 |
} |
||
2028 |
|||
2029 |
70 |
const int nid = EC_GROUP_get_curve_name(group); |
|
2030 |
✓✗ | 70 |
if (nid != 0) { |
2031 |
// Curve is well-known, get its OID and NIST nick-name (if it has one). |
||
2032 |
|||
2033 |
✓✗ | 70 |
if (const char* sn = OBJ_nid2sn(nid)) { |
2034 |
info->Set(context, env->asn1curve_string(), |
||
2035 |
280 |
OneByteString(env->isolate(), sn)).Check(); |
|
2036 |
} |
||
2037 |
|||
2038 |
✓✗ | 70 |
if (const char* nist = EC_curve_nid2nist(nid)) { |
2039 |
info->Set(context, env->nistcurve_string(), |
||
2040 |
280 |
OneByteString(env->isolate(), nist)).Check(); |
|
2041 |
} |
||
2042 |
} else { |
||
2043 |
// Unnamed curves can be described by their mathematical properties, |
||
2044 |
// but aren't used much (at all?) with X.509/TLS. Support later if needed. |
||
2045 |
} |
||
2046 |
} |
||
2047 |
|||
2048 |
1356 |
pkey.reset(); |
|
2049 |
1356 |
rsa.reset(); |
|
2050 |
1356 |
ec.reset(); |
|
2051 |
|||
2052 |
1356 |
ASN1_TIME_print(bio.get(), X509_get_notBefore(cert)); |
|
2053 |
1356 |
BIO_get_mem_ptr(bio.get(), &mem); |
|
2054 |
info->Set(context, env->valid_from_string(), |
||
2055 |
String::NewFromUtf8(env->isolate(), mem->data, |
||
2056 |
NewStringType::kNormal, |
||
2057 |
5424 |
mem->length).ToLocalChecked()).Check(); |
|
2058 |
1356 |
USE(BIO_reset(bio.get())); |
|
2059 |
|||
2060 |
1356 |
ASN1_TIME_print(bio.get(), X509_get_notAfter(cert)); |
|
2061 |
1356 |
BIO_get_mem_ptr(bio.get(), &mem); |
|
2062 |
info->Set(context, env->valid_to_string(), |
||
2063 |
String::NewFromUtf8(env->isolate(), mem->data, |
||
2064 |
NewStringType::kNormal, |
||
2065 |
5424 |
mem->length).ToLocalChecked()).Check(); |
|
2066 |
1356 |
bio.reset(); |
|
2067 |
|||
2068 |
unsigned char md[EVP_MAX_MD_SIZE]; |
||
2069 |
unsigned int md_size; |
||
2070 |
char fingerprint[EVP_MAX_MD_SIZE * 3 + 1]; |
||
2071 |
✓✗ | 1356 |
if (X509_digest(cert, EVP_sha1(), md, &md_size)) { |
2072 |
1356 |
AddFingerprintDigest(md, md_size, &fingerprint); |
|
2073 |
info->Set(context, env->fingerprint_string(), |
||
2074 |
5424 |
OneByteString(env->isolate(), fingerprint)).Check(); |
|
2075 |
} |
||
2076 |
✓✗ | 1356 |
if (X509_digest(cert, EVP_sha256(), md, &md_size)) { |
2077 |
1356 |
AddFingerprintDigest(md, md_size, &fingerprint); |
|
2078 |
info->Set(context, env->fingerprint256_string(), |
||
2079 |
5424 |
OneByteString(env->isolate(), fingerprint)).Check(); |
|
2080 |
} |
||
2081 |
|||
2082 |
StackOfASN1 eku(static_cast<STACK_OF(ASN1_OBJECT)*>( |
||
2083 |
1356 |
X509_get_ext_d2i(cert, NID_ext_key_usage, nullptr, nullptr))); |
|
2084 |
✓✓ | 1356 |
if (eku) { |
2085 |
150 |
Local<Array> ext_key_usage = Array::New(env->isolate()); |
|
2086 |
char buf[256]; |
||
2087 |
|||
2088 |
150 |
int j = 0; |
|
2089 |
✓✓ | 446 |
for (int i = 0; i < sk_ASN1_OBJECT_num(eku.get()); i++) { |
2090 |
✓✗ | 296 |
if (OBJ_obj2txt(buf, |
2091 |
sizeof(buf), |
||
2092 |
296 |
sk_ASN1_OBJECT_value(eku.get(), i), 1) >= 0) { |
|
2093 |
296 |
ext_key_usage->Set(context, |
|
2094 |
j++, |
||
2095 |
1184 |
OneByteString(env->isolate(), buf)).Check(); |
|
2096 |
} |
||
2097 |
} |
||
2098 |
|||
2099 |
150 |
eku.reset(); |
|
2100 |
450 |
info->Set(context, env->ext_key_usage_string(), ext_key_usage).Check(); |
|
2101 |
} |
||
2102 |
|||
2103 |
✓✗ | 1356 |
if (ASN1_INTEGER* serial_number = X509_get_serialNumber(cert)) { |
2104 |
1356 |
BignumPointer bn(ASN1_INTEGER_to_BN(serial_number, nullptr)); |
|
2105 |
✓✗ | 1356 |
if (bn) { |
2106 |
1356 |
OpenSSLBuffer buf(BN_bn2hex(bn.get())); |
|
2107 |
✓✗ | 1356 |
if (buf) { |
2108 |
info->Set(context, env->serial_number_string(), |
||
2109 |
5424 |
OneByteString(env->isolate(), buf.get())).Check(); |
|
2110 |
1356 |
} |
|
2111 |
1356 |
} |
|
2112 |
} |
||
2113 |
|||
2114 |
// Raw DER certificate |
||
2115 |
1356 |
int size = i2d_X509(cert, nullptr); |
|
2116 |
2712 |
Local<Object> buff = Buffer::New(env, size).ToLocalChecked(); |
|
2117 |
unsigned char* serialized = reinterpret_cast<unsigned char*>( |
||
2118 |
1356 |
Buffer::Data(buff)); |
|
2119 |
1356 |
i2d_X509(cert, &serialized); |
|
2120 |
4068 |
info->Set(context, env->raw_string(), buff).Check(); |
|
2121 |
|||
2122 |
2712 |
return scope.Escape(info); |
|
2123 |
} |
||
2124 |
|||
2125 |
|||
2126 |
454 |
static Local<Object> AddIssuerChainToObject(X509Pointer* cert, |
|
2127 |
Local<Object> object, |
||
2128 |
StackOfX509&& peer_certs, |
||
2129 |
Environment* const env) { |
||
2130 |
454 |
Local<Context> context = env->isolate()->GetCurrentContext(); |
|
2131 |
454 |
cert->reset(sk_X509_delete(peer_certs.get(), 0)); |
|
2132 |
for (;;) { |
||
2133 |
int i; |
||
2134 |
✓✓ | 956 |
for (i = 0; i < sk_X509_num(peer_certs.get()); i++) { |
2135 |
424 |
X509* ca = sk_X509_value(peer_certs.get(), i); |
|
2136 |
✓✓ | 424 |
if (X509_check_issued(ca, cert->get()) != X509_V_OK) |
2137 |
2 |
continue; |
|
2138 |
|||
2139 |
422 |
Local<Object> ca_info = X509ToObject(env, ca); |
|
2140 |
1266 |
object->Set(context, env->issuercert_string(), ca_info).Check(); |
|
2141 |
422 |
object = ca_info; |
|
2142 |
|||
2143 |
// NOTE: Intentionally freeing cert that is not used anymore. |
||
2144 |
// Delete cert and continue aggregating issuers. |
||
2145 |
422 |
cert->reset(sk_X509_delete(peer_certs.get(), i)); |
|
2146 |
422 |
break; |
|
2147 |
} |
||
2148 |
|||
2149 |
// Issuer not found, break out of the loop. |
||
2150 |
✓✓ | 476 |
if (i == sk_X509_num(peer_certs.get())) |
2151 |
454 |
break; |
|
2152 |
22 |
} |
|
2153 |
454 |
return object; |
|
2154 |
} |
||
2155 |
|||
2156 |
|||
2157 |
454 |
static StackOfX509 CloneSSLCerts(X509Pointer&& cert, |
|
2158 |
const STACK_OF(X509)* const ssl_certs) { |
||
2159 |
454 |
StackOfX509 peer_certs(sk_X509_new(nullptr)); |
|
2160 |
✗✓ | 454 |
if (cert) |
2161 |
sk_X509_push(peer_certs.get(), cert.release()); |
||
2162 |
✓✓ | 1332 |
for (int i = 0; i < sk_X509_num(ssl_certs); i++) { |
2163 |
878 |
X509Pointer cert(X509_dup(sk_X509_value(ssl_certs, i))); |
|
2164 |
✓✗✗✓ ✗✓ |
878 |
if (!cert || !sk_X509_push(peer_certs.get(), cert.get())) |
2165 |
return StackOfX509(); |
||
2166 |
// `cert` is now managed by the stack. |
||
2167 |
✓✗ | 878 |
cert.release(); |
2168 |
878 |
} |
|
2169 |
454 |
return peer_certs; |
|
2170 |
} |
||
2171 |
|||
2172 |
|||
2173 |
454 |
static Local<Object> GetLastIssuedCert(X509Pointer* cert, |
|
2174 |
const SSLPointer& ssl, |
||
2175 |
Local<Object> issuer_chain, |
||
2176 |
Environment* const env) { |
||
2177 |
454 |
Local<Context> context = env->isolate()->GetCurrentContext(); |
|
2178 |
✓✓ | 1334 |
while (X509_check_issued(cert->get(), cert->get()) != X509_V_OK) { |
2179 |
X509* ca; |
||
2180 |
✗✓ | 426 |
if (SSL_CTX_get_issuer(SSL_get_SSL_CTX(ssl.get()), cert->get(), &ca) <= 0) |
2181 |
break; |
||
2182 |
|||
2183 |
426 |
Local<Object> ca_info = X509ToObject(env, ca); |
|
2184 |
1278 |
issuer_chain->Set(context, env->issuercert_string(), ca_info).Check(); |
|
2185 |
426 |
issuer_chain = ca_info; |
|
2186 |
|||
2187 |
// Delete previous cert and continue aggregating issuers. |
||
2188 |
426 |
cert->reset(ca); |
|
2189 |
} |
||
2190 |
454 |
return issuer_chain; |
|
2191 |
} |
||
2192 |
|||
2193 |
|||
2194 |
template <class Base> |
||
2195 |
500 |
void SSLWrap<Base>::GetPeerCertificate( |
|
2196 |
const FunctionCallbackInfo<Value>& args) { |
||
2197 |
Base* w; |
||
2198 |
✗✓ | 1000 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2199 |
500 |
Environment* env = w->ssl_env(); |
|
2200 |
|||
2201 |
ClearErrorOnReturn clear_error_on_return; |
||
2202 |
|||
2203 |
Local<Object> result; |
||
2204 |
// Used to build the issuer certificate chain. |
||
2205 |
Local<Object> issuer_chain; |
||
2206 |
|||
2207 |
// NOTE: This is because of the odd OpenSSL behavior. On client `cert_chain` |
||
2208 |
// contains the `peer_certificate`, but on server it doesn't. |
||
2209 |
X509Pointer cert( |
||
2210 |
✓✓ | 1000 |
w->is_server() ? SSL_get_peer_certificate(w->ssl_.get()) : nullptr); |
2211 |
500 |
STACK_OF(X509)* ssl_certs = SSL_get_peer_cert_chain(w->ssl_.get()); |
|
2212 |
✓✓✓✓ ✗✓✓✓ |
500 |
if (!cert && (ssl_certs == nullptr || sk_X509_num(ssl_certs) == 0)) |
2213 |
3 |
goto done; |
|
2214 |
|||
2215 |
// Short result requested. |
||
2216 |
✓✗✓✓ ✓✗✓✓ |
1988 |
if (args.Length() < 1 || !args[0]->IsTrue()) { |
2217 |
✓✓ | 43 |
result = X509ToObject(env, cert ? cert.get() : sk_X509_value(ssl_certs, 0)); |
2218 |
43 |
goto done; |
|
2219 |
} |
||
2220 |
|||
2221 |
✓✗ | 908 |
if (auto peer_certs = CloneSSLCerts(std::move(cert), ssl_certs)) { |
2222 |
// First and main certificate. |
||
2223 |
454 |
X509Pointer cert(sk_X509_value(peer_certs.get(), 0)); |
|
2224 |
✗✓ | 454 |
CHECK(cert); |
2225 |
454 |
result = X509ToObject(env, cert.release()); |
|
2226 |
|||
2227 |
454 |
issuer_chain = |
|
2228 |
454 |
AddIssuerChainToObject(&cert, result, std::move(peer_certs), env); |
|
2229 |
454 |
issuer_chain = GetLastIssuedCert(&cert, w->ssl_, issuer_chain, env); |
|
2230 |
// Last certificate should be self-signed. |
||
2231 |
✓✗ | 454 |
if (X509_check_issued(cert.get(), cert.get()) == X509_V_OK) |
2232 |
issuer_chain->Set(env->context(), |
||
2233 |
env->issuercert_string(), |
||
2234 |
1816 |
issuer_chain).Check(); |
|
2235 |
} |
||
2236 |
|||
2237 |
done: |
||
2238 |
1500 |
args.GetReturnValue().Set(result); |
|
2239 |
} |
||
2240 |
|||
2241 |
|||
2242 |
template <class Base> |
||
2243 |
12 |
void SSLWrap<Base>::GetCertificate( |
|
2244 |
const FunctionCallbackInfo<Value>& args) { |
||
2245 |
Base* w; |
||
2246 |
✗✓ | 24 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2247 |
12 |
Environment* env = w->ssl_env(); |
|
2248 |
|||
2249 |
ClearErrorOnReturn clear_error_on_return; |
||
2250 |
|||
2251 |
Local<Object> result; |
||
2252 |
|||
2253 |
12 |
X509* cert = SSL_get_certificate(w->ssl_.get()); |
|
2254 |
|||
2255 |
✓✓ | 12 |
if (cert != nullptr) |
2256 |
11 |
result = X509ToObject(env, cert); |
|
2257 |
|||
2258 |
24 |
args.GetReturnValue().Set(result); |
|
2259 |
} |
||
2260 |
|||
2261 |
|||
2262 |
template <class Base> |
||
2263 |
3 |
void SSLWrap<Base>::GetFinished(const FunctionCallbackInfo<Value>& args) { |
|
2264 |
3 |
Environment* env = Environment::GetCurrent(args); |
|
2265 |
|||
2266 |
Base* w; |
||
2267 |
✗✓ | 4 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2268 |
|||
2269 |
// We cannot just pass nullptr to SSL_get_finished() |
||
2270 |
// because it would further be propagated to memcpy(), |
||
2271 |
// where the standard requirements as described in ISO/IEC 9899:2011 |
||
2272 |
// sections 7.21.2.1, 7.21.1.2, and 7.1.4, would be violated. |
||
2273 |
// Thus, we use a dummy byte. |
||
2274 |
char dummy[1]; |
||
2275 |
3 |
size_t len = SSL_get_finished(w->ssl_.get(), dummy, sizeof dummy); |
|
2276 |
✓✓ | 3 |
if (len == 0) |
2277 |
1 |
return; |
|
2278 |
|||
2279 |
2 |
AllocatedBuffer buf = env->AllocateManaged(len); |
|
2280 |
✗✓ | 2 |
CHECK_EQ(len, SSL_get_finished(w->ssl_.get(), buf.data(), len)); |
2281 |
6 |
args.GetReturnValue().Set(buf.ToBuffer().ToLocalChecked()); |
|
2282 |
} |
||
2283 |
|||
2284 |
|||
2285 |
template <class Base> |
||
2286 |
3 |
void SSLWrap<Base>::GetPeerFinished(const FunctionCallbackInfo<Value>& args) { |
|
2287 |
3 |
Environment* env = Environment::GetCurrent(args); |
|
2288 |
|||
2289 |
Base* w; |
||
2290 |
✗✓ | 4 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2291 |
|||
2292 |
// We cannot just pass nullptr to SSL_get_peer_finished() |
||
2293 |
// because it would further be propagated to memcpy(), |
||
2294 |
// where the standard requirements as described in ISO/IEC 9899:2011 |
||
2295 |
// sections 7.21.2.1, 7.21.1.2, and 7.1.4, would be violated. |
||
2296 |
// Thus, we use a dummy byte. |
||
2297 |
char dummy[1]; |
||
2298 |
3 |
size_t len = SSL_get_peer_finished(w->ssl_.get(), dummy, sizeof dummy); |
|
2299 |
✓✓ | 3 |
if (len == 0) |
2300 |
1 |
return; |
|
2301 |
|||
2302 |
2 |
AllocatedBuffer buf = env->AllocateManaged(len); |
|
2303 |
✗✓ | 2 |
CHECK_EQ(len, SSL_get_peer_finished(w->ssl_.get(), buf.data(), len)); |
2304 |
6 |
args.GetReturnValue().Set(buf.ToBuffer().ToLocalChecked()); |
|
2305 |
} |
||
2306 |
|||
2307 |
|||
2308 |
template <class Base> |
||
2309 |
19 |
void SSLWrap<Base>::GetSession(const FunctionCallbackInfo<Value>& args) { |
|
2310 |
19 |
Environment* env = Environment::GetCurrent(args); |
|
2311 |
|||
2312 |
Base* w; |
||
2313 |
✗✓ | 19 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2314 |
|||
2315 |
19 |
SSL_SESSION* sess = SSL_get_session(w->ssl_.get()); |
|
2316 |
✗✓ | 19 |
if (sess == nullptr) |
2317 |
return; |
||
2318 |
|||
2319 |
19 |
int slen = i2d_SSL_SESSION(sess, nullptr); |
|
2320 |
✗✓ | 19 |
if (slen <= 0) |
2321 |
return; // Invalid or malformed session. |
||
2322 |
|||
2323 |
19 |
AllocatedBuffer sbuf = env->AllocateManaged(slen); |
|
2324 |
19 |
unsigned char* p = reinterpret_cast<unsigned char*>(sbuf.data()); |
|
2325 |
✗✓ | 19 |
CHECK_LT(0, i2d_SSL_SESSION(sess, &p)); |
2326 |
57 |
args.GetReturnValue().Set(sbuf.ToBuffer().ToLocalChecked()); |
|
2327 |
} |
||
2328 |
|||
2329 |
|||
2330 |
template <class Base> |
||
2331 |
124 |
void SSLWrap<Base>::SetSession(const FunctionCallbackInfo<Value>& args) { |
|
2332 |
124 |
Environment* env = Environment::GetCurrent(args); |
|
2333 |
|||
2334 |
Base* w; |
||
2335 |
✗✓ | 124 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2336 |
|||
2337 |
✗✓ | 124 |
if (args.Length() < 1) { |
2338 |
return THROW_ERR_MISSING_ARGS(env, "Session argument is mandatory"); |
||
2339 |
} |
||
2340 |
|||
2341 |
✗✓ | 124 |
THROW_AND_RETURN_IF_NOT_BUFFER(env, args[0], "Session"); |
2342 |
248 |
ArrayBufferViewContents<unsigned char> sbuf(args[0].As<ArrayBufferView>()); |
|
2343 |
|||
2344 |
124 |
const unsigned char* p = sbuf.data(); |
|
2345 |
124 |
SSLSessionPointer sess(d2i_SSL_SESSION(nullptr, &p, sbuf.length())); |
|
2346 |
|||
2347 |
✗✓ | 124 |
if (sess == nullptr) |
2348 |
return; |
||
2349 |
|||
2350 |
124 |
int r = SSL_set_session(w->ssl_.get(), sess.get()); |
|
2351 |
|||
2352 |
✗✓ | 124 |
if (!r) |
2353 |
return env->ThrowError("SSL_set_session error"); |
||
2354 |
} |
||
2355 |
|||
2356 |
|||
2357 |
template <class Base> |
||
2358 |
10 |
void SSLWrap<Base>::LoadSession(const FunctionCallbackInfo<Value>& args) { |
|
2359 |
Base* w; |
||
2360 |
✗✓ | 20 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2361 |
|||
2362 |
// TODO(@sam-github) check arg length and types in js, and CHECK in c++ |
||
2363 |
✓✗✓✗ ✓✗ |
20 |
if (args.Length() >= 1 && Buffer::HasInstance(args[0])) { |
2364 |
10 |
ArrayBufferViewContents<unsigned char> sbuf(args[0]); |
|
2365 |
|||
2366 |
10 |
const unsigned char* p = sbuf.data(); |
|
2367 |
10 |
SSL_SESSION* sess = d2i_SSL_SESSION(nullptr, &p, sbuf.length()); |
|
2368 |
|||
2369 |
// Setup next session and move hello to the BIO buffer |
||
2370 |
10 |
w->next_sess_.reset(sess); |
|
2371 |
} |
||
2372 |
} |
||
2373 |
|||
2374 |
|||
2375 |
template <class Base> |
||
2376 |
535 |
void SSLWrap<Base>::IsSessionReused(const FunctionCallbackInfo<Value>& args) { |
|
2377 |
Base* w; |
||
2378 |
✗✓ | 1070 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2379 |
535 |
bool yes = SSL_session_reused(w->ssl_.get()); |
|
2380 |
1605 |
args.GetReturnValue().Set(yes); |
|
2381 |
} |
||
2382 |
|||
2383 |
|||
2384 |
template <class Base> |
||
2385 |
19 |
void SSLWrap<Base>::EndParser(const FunctionCallbackInfo<Value>& args) { |
|
2386 |
Base* w; |
||
2387 |
✗✓ | 38 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2388 |
19 |
w->hello_parser_.End(); |
|
2389 |
} |
||
2390 |
|||
2391 |
|||
2392 |
template <class Base> |
||
2393 |
92 |
void SSLWrap<Base>::Renegotiate(const FunctionCallbackInfo<Value>& args) { |
|
2394 |
Base* w; |
||
2395 |
✗✓ | 93 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2396 |
|||
2397 |
ClearErrorOnReturn clear_error_on_return; |
||
2398 |
|||
2399 |
✓✓ | 92 |
if (SSL_renegotiate(w->ssl_.get()) != 1) { |
2400 |
✓✓ | 1 |
return ThrowCryptoError(w->ssl_env(), ERR_get_error()); |
2401 |
91 |
} |
|
2402 |
} |
||
2403 |
|||
2404 |
|||
2405 |
template <class Base> |
||
2406 |
18 |
void SSLWrap<Base>::GetTLSTicket(const FunctionCallbackInfo<Value>& args) { |
|
2407 |
Base* w; |
||
2408 |
✗✓ | 18 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2409 |
18 |
Environment* env = w->ssl_env(); |
|
2410 |
|||
2411 |
18 |
SSL_SESSION* sess = SSL_get_session(w->ssl_.get()); |
|
2412 |
✗✓ | 18 |
if (sess == nullptr) |
2413 |
return; |
||
2414 |
|||
2415 |
const unsigned char* ticket; |
||
2416 |
size_t length; |
||
2417 |
18 |
SSL_SESSION_get0_ticket(sess, &ticket, &length); |
|
2418 |
|||
2419 |
✗✓ | 18 |
if (ticket == nullptr) |
2420 |
return; |
||
2421 |
|||
2422 |
Local<Object> buff = Buffer::Copy( |
||
2423 |
36 |
env, reinterpret_cast<const char*>(ticket), length).ToLocalChecked(); |
|
2424 |
|||
2425 |
36 |
args.GetReturnValue().Set(buff); |
|
2426 |
} |
||
2427 |
|||
2428 |
|||
2429 |
template <class Base> |
||
2430 |
8 |
void SSLWrap<Base>::NewSessionDone(const FunctionCallbackInfo<Value>& args) { |
|
2431 |
Base* w; |
||
2432 |
✗✓ | 16 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2433 |
8 |
w->awaiting_new_session_ = false; |
|
2434 |
8 |
w->NewSessionDoneCb(); |
|
2435 |
} |
||
2436 |
|||
2437 |
|||
2438 |
template <class Base> |
||
2439 |
2 |
void SSLWrap<Base>::SetOCSPResponse(const FunctionCallbackInfo<Value>& args) { |
|
2440 |
Base* w; |
||
2441 |
✗✓ | 2 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2442 |
2 |
Environment* env = w->env(); |
|
2443 |
|||
2444 |
✗✓ | 2 |
if (args.Length() < 1) |
2445 |
return THROW_ERR_MISSING_ARGS(env, "OCSP response argument is mandatory"); |
||
2446 |
|||
2447 |
✗✓ | 2 |
THROW_AND_RETURN_IF_NOT_BUFFER(env, args[0], "OCSP response"); |
2448 |
|||
2449 |
8 |
w->ocsp_response_.Reset(args.GetIsolate(), args[0].As<ArrayBufferView>()); |
|
2450 |
} |
||
2451 |
|||
2452 |
|||
2453 |
template <class Base> |
||
2454 |
4 |
void SSLWrap<Base>::RequestOCSP(const FunctionCallbackInfo<Value>& args) { |
|
2455 |
Base* w; |
||
2456 |
✗✓ | 8 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2457 |
|||
2458 |
4 |
SSL_set_tlsext_status_type(w->ssl_.get(), TLSEXT_STATUSTYPE_ocsp); |
|
2459 |
} |
||
2460 |
|||
2461 |
|||
2462 |
template <class Base> |
||
2463 |
888 |
void SSLWrap<Base>::GetEphemeralKeyInfo( |
|
2464 |
const FunctionCallbackInfo<Value>& args) { |
||
2465 |
Base* w; |
||
2466 |
✗✓ | 888 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2467 |
888 |
Environment* env = Environment::GetCurrent(args); |
|
2468 |
888 |
Local<Context> context = env->context(); |
|
2469 |
|||
2470 |
✗✓ | 888 |
CHECK(w->ssl_); |
2471 |
|||
2472 |
// tmp key is available on only client |
||
2473 |
✓✓ | 888 |
if (w->is_server()) |
2474 |
14 |
return args.GetReturnValue().SetNull(); |
|
2475 |
|||
2476 |
881 |
Local<Object> info = Object::New(env->isolate()); |
|
2477 |
|||
2478 |
EVP_PKEY* raw_key; |
||
2479 |
✓✓ | 881 |
if (SSL_get_server_tmp_key(w->ssl_.get(), &raw_key)) { |
2480 |
823 |
EVPKeyPointer key(raw_key); |
|
2481 |
823 |
int kid = EVP_PKEY_id(key.get()); |
|
2482 |
✓✓✗ | 823 |
switch (kid) { |
2483 |
case EVP_PKEY_DH: |
||
2484 |
info->Set(context, env->type_string(), |
||
2485 |
24 |
FIXED_ONE_BYTE_STRING(env->isolate(), "DH")).Check(); |
|
2486 |
info->Set(context, env->size_string(), |
||
2487 |
24 |
Integer::New(env->isolate(), EVP_PKEY_bits(key.get()))) |
|
2488 |
12 |
.Check(); |
|
2489 |
6 |
break; |
|
2490 |
case EVP_PKEY_EC: |
||
2491 |
case EVP_PKEY_X25519: |
||
2492 |
case EVP_PKEY_X448: |
||
2493 |
{ |
||
2494 |
const char* curve_name; |
||
2495 |
✓✓ | 817 |
if (kid == EVP_PKEY_EC) { |
2496 |
7 |
EC_KEY* ec = EVP_PKEY_get1_EC_KEY(key.get()); |
|
2497 |
7 |
int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); |
|
2498 |
7 |
curve_name = OBJ_nid2sn(nid); |
|
2499 |
7 |
EC_KEY_free(ec); |
|
2500 |
} else { |
||
2501 |
810 |
curve_name = OBJ_nid2sn(kid); |
|
2502 |
} |
||
2503 |
info->Set(context, env->type_string(), |
||
2504 |
3268 |
FIXED_ONE_BYTE_STRING(env->isolate(), "ECDH")).Check(); |
|
2505 |
info->Set(context, env->name_string(), |
||
2506 |
OneByteString(args.GetIsolate(), |
||
2507 |
3268 |
curve_name)).Check(); |
|
2508 |
info->Set(context, env->size_string(), |
||
2509 |
Integer::New(env->isolate(), |
||
2510 |
3268 |
EVP_PKEY_bits(key.get()))).Check(); |
|
2511 |
} |
||
2512 |
817 |
break; |
|
2513 |
default: |
||
2514 |
break; |
||
2515 |
823 |
} |
|
2516 |
} |
||
2517 |
// TODO(@sam-github) semver-major: else return ThrowCryptoError(env, |
||
2518 |
// ERR_get_error()) |
||
2519 |
|||
2520 |
1762 |
return args.GetReturnValue().Set(info); |
|
2521 |
} |
||
2522 |
|||
2523 |
|||
2524 |
#ifdef SSL_set_max_send_fragment |
||
2525 |
template <class Base> |
||
2526 |
3 |
void SSLWrap<Base>::SetMaxSendFragment( |
|
2527 |
const FunctionCallbackInfo<Value>& args) { |
||
2528 |
✓✗✗✓ ✓✗✗✓ |
12 |
CHECK(args.Length() >= 1 && args[0]->IsNumber()); |
2529 |
|||
2530 |
Base* w; |
||
2531 |
✗✓ | 6 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2532 |
|||
2533 |
12 |
int rv = SSL_set_max_send_fragment( |
|
2534 |
w->ssl_.get(), |
||
2535 |
args[0]->Int32Value(w->ssl_env()->context()).FromJust()); |
||
2536 |
6 |
args.GetReturnValue().Set(rv); |
|
2537 |
} |
||
2538 |
#endif // SSL_set_max_send_fragment |
||
2539 |
|||
2540 |
|||
2541 |
template <class Base> |
||
2542 |
951 |
void SSLWrap<Base>::VerifyError(const FunctionCallbackInfo<Value>& args) { |
|
2543 |
Base* w; |
||
2544 |
✗✓ | 1476 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2545 |
|||
2546 |
// XXX(bnoordhuis) The UNABLE_TO_GET_ISSUER_CERT error when there is no |
||
2547 |
// peer certificate is questionable but it's compatible with what was |
||
2548 |
// here before. |
||
2549 |
long x509_verify_error = // NOLINT(runtime/int) |
||
2550 |
951 |
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT; |
|
2551 |
✓✓ | 951 |
if (X509* peer_cert = SSL_get_peer_certificate(w->ssl_.get())) { |
2552 |
950 |
X509_free(peer_cert); |
|
2553 |
950 |
x509_verify_error = SSL_get_verify_result(w->ssl_.get()); |
|
2554 |
} |
||
2555 |
|||
2556 |
✓✓ | 951 |
if (x509_verify_error == X509_V_OK) |
2557 |
1050 |
return args.GetReturnValue().SetNull(); |
|
2558 |
|||
2559 |
426 |
const char* reason = X509_verify_cert_error_string(x509_verify_error); |
|
2560 |
426 |
const char* code = reason; |
|
2561 |
#define CASE_X509_ERR(CODE) case X509_V_ERR_##CODE: code = #CODE; break; |
||
2562 |
✓✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✓✓✓ ✗✓✗✗ ✓✗✗✗ |
426 |
switch (x509_verify_error) { |
2563 |
1 |
CASE_X509_ERR(UNABLE_TO_GET_ISSUER_CERT) |
|
2564 |
1 |
CASE_X509_ERR(UNABLE_TO_GET_CRL) |
|
2565 |
CASE_X509_ERR(UNABLE_TO_DECRYPT_CERT_SIGNATURE) |
||
2566 |
CASE_X509_ERR(UNABLE_TO_DECRYPT_CRL_SIGNATURE) |
||
2567 |
CASE_X509_ERR(UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY) |
||
2568 |
CASE_X509_ERR(CERT_SIGNATURE_FAILURE) |
||
2569 |
CASE_X509_ERR(CRL_SIGNATURE_FAILURE) |
||
2570 |
CASE_X509_ERR(CERT_NOT_YET_VALID) |
||
2571 |
CASE_X509_ERR(CERT_HAS_EXPIRED) |
||
2572 |
CASE_X509_ERR(CRL_NOT_YET_VALID) |
||
2573 |
CASE_X509_ERR(CRL_HAS_EXPIRED) |
||
2574 |
CASE_X509_ERR(ERROR_IN_CERT_NOT_BEFORE_FIELD) |
||
2575 |
CASE_X509_ERR(ERROR_IN_CERT_NOT_AFTER_FIELD) |
||
2576 |
CASE_X509_ERR(ERROR_IN_CRL_LAST_UPDATE_FIELD) |
||
2577 |
CASE_X509_ERR(ERROR_IN_CRL_NEXT_UPDATE_FIELD) |
||
2578 |
CASE_X509_ERR(OUT_OF_MEM) |
||
2579 |
249 |
CASE_X509_ERR(DEPTH_ZERO_SELF_SIGNED_CERT) |
|
2580 |
13 |
CASE_X509_ERR(SELF_SIGNED_CERT_IN_CHAIN) |
|
2581 |
4 |
CASE_X509_ERR(UNABLE_TO_GET_ISSUER_CERT_LOCALLY) |
|
2582 |
156 |
CASE_X509_ERR(UNABLE_TO_VERIFY_LEAF_SIGNATURE) |
|
2583 |
CASE_X509_ERR(CERT_CHAIN_TOO_LONG) |
||
2584 |
1 |
CASE_X509_ERR(CERT_REVOKED) |
|
2585 |
CASE_X509_ERR(INVALID_CA) |
||
2586 |
CASE_X509_ERR(PATH_LENGTH_EXCEEDED) |
||
2587 |
1 |
CASE_X509_ERR(INVALID_PURPOSE) |
|
2588 |
CASE_X509_ERR(CERT_UNTRUSTED) |
||
2589 |
CASE_X509_ERR(CERT_REJECTED) |
||
2590 |
} |
||
2591 |
#undef CASE_X509_ERR |
||
2592 |
|||
2593 |
426 |
Isolate* isolate = args.GetIsolate(); |
|
2594 |
426 |
Local<String> reason_string = OneByteString(isolate, reason); |
|
2595 |
426 |
Local<Value> exception_value = Exception::Error(reason_string); |
|
2596 |
Local<Object> exception_object = |
||
2597 |
1278 |
exception_value->ToObject(isolate->GetCurrentContext()).ToLocalChecked(); |
|
2598 |
2130 |
exception_object->Set(w->env()->context(), w->env()->code_string(), |
|
2599 |
OneByteString(isolate, code)).Check(); |
||
2600 |
852 |
args.GetReturnValue().Set(exception_object); |
|
2601 |
} |
||
2602 |
|||
2603 |
|||
2604 |
template <class Base> |
||
2605 |
49 |
void SSLWrap<Base>::GetCipher(const FunctionCallbackInfo<Value>& args) { |
|
2606 |
Base* w; |
||
2607 |
✗✓ | 49 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2608 |
49 |
Environment* env = w->ssl_env(); |
|
2609 |
49 |
Local<Context> context = env->context(); |
|
2610 |
|||
2611 |
49 |
const SSL_CIPHER* c = SSL_get_current_cipher(w->ssl_.get()); |
|
2612 |
✗✓ | 49 |
if (c == nullptr) |
2613 |
return; |
||
2614 |
|||
2615 |
49 |
Local<Object> info = Object::New(env->isolate()); |
|
2616 |
49 |
const char* cipher_name = SSL_CIPHER_get_name(c); |
|
2617 |
info->Set(context, env->name_string(), |
||
2618 |
196 |
OneByteString(args.GetIsolate(), cipher_name)).Check(); |
|
2619 |
49 |
const char* cipher_version = SSL_CIPHER_get_version(c); |
|
2620 |
info->Set(context, env->version_string(), |
||
2621 |
196 |
OneByteString(args.GetIsolate(), cipher_version)).Check(); |
|
2622 |
98 |
args.GetReturnValue().Set(info); |
|
2623 |
} |
||
2624 |
|||
2625 |
|||
2626 |
template <class Base> |
||
2627 |
547 |
void SSLWrap<Base>::GetProtocol(const FunctionCallbackInfo<Value>& args) { |
|
2628 |
Base* w; |
||
2629 |
✗✓ | 1094 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2630 |
|||
2631 |
547 |
const char* tls_version = SSL_get_version(w->ssl_.get()); |
|
2632 |
1641 |
args.GetReturnValue().Set(OneByteString(args.GetIsolate(), tls_version)); |
|
2633 |
} |
||
2634 |
|||
2635 |
|||
2636 |
template <class Base> |
||
2637 |
25 |
int SSLWrap<Base>::SelectALPNCallback(SSL* s, |
|
2638 |
const unsigned char** out, |
||
2639 |
unsigned char* outlen, |
||
2640 |
const unsigned char* in, |
||
2641 |
unsigned int inlen, |
||
2642 |
void* arg) { |
||
2643 |
25 |
Base* w = static_cast<Base*>(SSL_get_app_data(s)); |
|
2644 |
25 |
Environment* env = w->env(); |
|
2645 |
25 |
HandleScope handle_scope(env->isolate()); |
|
2646 |
25 |
Context::Scope context_scope(env->context()); |
|
2647 |
|||
2648 |
Local<Value> alpn_buffer = |
||
2649 |
25 |
w->object()->GetPrivate( |
|
2650 |
env->context(), |
||
2651 |
100 |
env->alpn_buffer_private_symbol()).ToLocalChecked(); |
|
2652 |
25 |
ArrayBufferViewContents<unsigned char> alpn_protos(alpn_buffer); |
|
2653 |
int status = SSL_select_next_proto(const_cast<unsigned char**>(out), outlen, |
||
2654 |
25 |
alpn_protos.data(), alpn_protos.length(), |
|
2655 |
25 |
in, inlen); |
|
2656 |
// According to 3.2. Protocol Selection of RFC7301, fatal |
||
2657 |
// no_application_protocol alert shall be sent but OpenSSL 1.0.2 does not |
||
2658 |
// support it yet. See |
||
2659 |
// https://rt.openssl.org/Ticket/Display.html?id=3463&user=guest&pass=guest |
||
2660 |
return status == OPENSSL_NPN_NEGOTIATED ? SSL_TLSEXT_ERR_OK |
||
2661 |
✓✓ | 50 |
: SSL_TLSEXT_ERR_NOACK; |
2662 |
} |
||
2663 |
|||
2664 |
|||
2665 |
template <class Base> |
||
2666 |
1702 |
void SSLWrap<Base>::GetALPNNegotiatedProto( |
|
2667 |
const FunctionCallbackInfo<Value>& args) { |
||
2668 |
Base* w; |
||
2669 |
✗✓ | 3404 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2670 |
|||
2671 |
const unsigned char* alpn_proto; |
||
2672 |
unsigned int alpn_proto_len; |
||
2673 |
|||
2674 |
1702 |
SSL_get0_alpn_selected(w->ssl_.get(), &alpn_proto, &alpn_proto_len); |
|
2675 |
|||
2676 |
Local<Value> result; |
||
2677 |
✓✓ | 1702 |
if (alpn_proto_len == 0) { |
2678 |
3312 |
result = False(args.GetIsolate()); |
|
2679 |
✓✓✓✗ |
86 |
} else if (alpn_proto_len == sizeof("h2") - 1 && |
2680 |
40 |
0 == memcmp(alpn_proto, "h2", sizeof("h2") - 1)) { |
|
2681 |
80 |
result = w->env()->h2_string(); |
|
2682 |
✓✓✓✗ |
8 |
} else if (alpn_proto_len == sizeof("http/1.1") - 1 && |
2683 |
2 |
0 == memcmp(alpn_proto, "http/1.1", sizeof("http/1.1") - 1)) { |
|
2684 |
4 |
result = w->env()->http_1_1_string(); |
|
2685 |
} else { |
||
2686 |
12 |
result = OneByteString(args.GetIsolate(), alpn_proto, alpn_proto_len); |
|
2687 |
} |
||
2688 |
|||
2689 |
3404 |
args.GetReturnValue().Set(result); |
|
2690 |
} |
||
2691 |
|||
2692 |
|||
2693 |
template <class Base> |
||
2694 |
198 |
void SSLWrap<Base>::SetALPNProtocols(const FunctionCallbackInfo<Value>& args) { |
|
2695 |
Base* w; |
||
2696 |
✗✓ | 198 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2697 |
198 |
Environment* env = w->env(); |
|
2698 |
✓✗✗✓ ✗✓ |
396 |
if (args.Length() < 1 || !Buffer::HasInstance(args[0])) |
2699 |
return env->ThrowTypeError("Must give a Buffer as first argument"); |
||
2700 |
|||
2701 |
✓✓ | 198 |
if (w->is_client()) { |
2702 |
30 |
ArrayBufferViewContents<unsigned char> alpn_protos(args[0]); |
|
2703 |
int r = SSL_set_alpn_protos( |
||
2704 |
30 |
w->ssl_.get(), alpn_protos.data(), alpn_protos.length()); |
|
2705 |
✗✓ | 30 |
CHECK_EQ(r, 0); |
2706 |
} else { |
||
2707 |
✗✓ | 504 |
CHECK( |
2708 |
w->object()->SetPrivate( |
||
2709 |
env->context(), |
||
2710 |
env->alpn_buffer_private_symbol(), |
||
2711 |
args[0]).FromJust()); |
||
2712 |
// Server should select ALPN protocol from list of advertised by client |
||
2713 |
336 |
SSL_CTX_set_alpn_select_cb(SSL_get_SSL_CTX(w->ssl_.get()), |
|
2714 |
SelectALPNCallback, |
||
2715 |
168 |
nullptr); |
|
2716 |
} |
||
2717 |
} |
||
2718 |
|||
2719 |
|||
2720 |
template <class Base> |
||
2721 |
8 |
int SSLWrap<Base>::TLSExtStatusCallback(SSL* s, void* arg) { |
|
2722 |
8 |
Base* w = static_cast<Base*>(SSL_get_app_data(s)); |
|
2723 |
8 |
Environment* env = w->env(); |
|
2724 |
8 |
HandleScope handle_scope(env->isolate()); |
|
2725 |
|||
2726 |
✓✓ | 8 |
if (w->is_client()) { |
2727 |
// Incoming response |
||
2728 |
const unsigned char* resp; |
||
2729 |
4 |
int len = SSL_get_tlsext_status_ocsp_resp(s, &resp); |
|
2730 |
Local<Value> arg; |
||
2731 |
✓✓ | 4 |
if (resp == nullptr) { |
2732 |
4 |
arg = Null(env->isolate()); |
|
2733 |
} else { |
||
2734 |
4 |
arg = |
|
2735 |
2 |
Buffer::Copy(env, reinterpret_cast<const char*>(resp), len) |
|
2736 |
.ToLocalChecked(); |
||
2737 |
} |
||
2738 |
|||
2739 |
4 |
w->MakeCallback(env->onocspresponse_string(), 1, &arg); |
|
2740 |
|||
2741 |
// No async acceptance is possible, so always return 1 to accept the |
||
2742 |
// response. The listener for 'OCSPResponse' event has no control over |
||
2743 |
// return value, but it can .destroy() the connection if the response is not |
||
2744 |
// acceptable. |
||
2745 |
4 |
return 1; |
|
2746 |
} else { |
||
2747 |
// Outgoing response |
||
2748 |
✓✓ | 8 |
if (w->ocsp_response_.IsEmpty()) |
2749 |
2 |
return SSL_TLSEXT_ERR_NOACK; |
|
2750 |
|||
2751 |
Local<ArrayBufferView> obj = PersistentToLocal::Default(env->isolate(), |
||
2752 |
2 |
w->ocsp_response_); |
|
2753 |
2 |
size_t len = obj->ByteLength(); |
|
2754 |
|||
2755 |
// OpenSSL takes control of the pointer after accepting it |
||
2756 |
2 |
unsigned char* data = MallocOpenSSL<unsigned char>(len); |
|
2757 |
2 |
obj->CopyContents(data, len); |
|
2758 |
|||
2759 |
✗✓ | 2 |
if (!SSL_set_tlsext_status_ocsp_resp(s, data, len)) |
2760 |
OPENSSL_free(data); |
||
2761 |
2 |
w->ocsp_response_.Reset(); |
|
2762 |
|||
2763 |
2 |
return SSL_TLSEXT_ERR_OK; |
|
2764 |
8 |
} |
|
2765 |
} |
||
2766 |
|||
2767 |
|||
2768 |
template <class Base> |
||
2769 |
22 |
void SSLWrap<Base>::WaitForCertCb(CertCb cb, void* arg) { |
|
2770 |
22 |
cert_cb_ = cb; |
|
2771 |
22 |
cert_cb_arg_ = arg; |
|
2772 |
22 |
} |
|
2773 |
|||
2774 |
|||
2775 |
template <class Base> |
||
2776 |
885 |
int SSLWrap<Base>::SSLCertCallback(SSL* s, void* arg) { |
|
2777 |
885 |
Base* w = static_cast<Base*>(SSL_get_app_data(s)); |
|
2778 |
|||
2779 |
✓✓ | 885 |
if (!w->is_server()) |
2780 |
42 |
return 1; |
|
2781 |
|||
2782 |
✓✓ | 843 |
if (!w->is_waiting_cert_cb()) |
2783 |
821 |
return 1; |
|
2784 |
|||
2785 |
✗✓ | 22 |
if (w->cert_cb_running_) |
2786 |
// Not an error. Suspend handshake with SSL_ERROR_WANT_X509_LOOKUP, and |
||
2787 |
// handshake will continue after certcb is done. |
||
2788 |
return -1; |
||
2789 |
|||
2790 |
22 |
Environment* env = w->env(); |
|
2791 |
22 |
Local<Context> context = env->context(); |
|
2792 |
22 |
HandleScope handle_scope(env->isolate()); |
|
2793 |
Context::Scope context_scope(context); |
||
2794 |
22 |
w->cert_cb_running_ = true; |
|
2795 |
|||
2796 |
22 |
Local<Object> info = Object::New(env->isolate()); |
|
2797 |
|||
2798 |
22 |
const char* servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); |
|
2799 |
✓✓ | 22 |
if (servername == nullptr) { |
2800 |
info->Set(context, |
||
2801 |
env->servername_string(), |
||
2802 |
16 |
String::Empty(env->isolate())).Check(); |
|
2803 |
} else { |
||
2804 |
Local<String> str = OneByteString(env->isolate(), servername, |
||
2805 |
18 |
strlen(servername)); |
|
2806 |
54 |
info->Set(context, env->servername_string(), str).Check(); |
|
2807 |
} |
||
2808 |
|||
2809 |
22 |
const bool ocsp = (SSL_get_tlsext_status_type(s) == TLSEXT_STATUSTYPE_ocsp); |
|
2810 |
info->Set(context, env->ocsp_request_string(), |
||
2811 |
88 |
Boolean::New(env->isolate(), ocsp)).Check(); |
|
2812 |
|||
2813 |
44 |
Local<Value> argv[] = { info }; |
|
2814 |
22 |
w->MakeCallback(env->oncertcb_string(), arraysize(argv), argv); |
|
2815 |
|||
2816 |
✓✓ | 22 |
if (!w->cert_cb_running_) |
2817 |
9 |
return 1; |
|
2818 |
|||
2819 |
// Performing async action, wait... |
||
2820 |
35 |
return -1; |
|
2821 |
} |
||
2822 |
|||
2823 |
|||
2824 |
template <class Base> |
||
2825 |
19 |
void SSLWrap<Base>::CertCbDone(const FunctionCallbackInfo<Value>& args) { |
|
2826 |
Base* w; |
||
2827 |
✗✓ | 22 |
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); |
2828 |
19 |
Environment* env = w->env(); |
|
2829 |
|||
2830 |
✓✗✗✓ ✗✓ |
19 |
CHECK(w->is_waiting_cert_cb() && w->cert_cb_running_); |
2831 |
|||
2832 |
19 |
Local<Object> object = w->object(); |
|
2833 |
Local<Value> ctx = object->Get(env->context(), |
||
2834 |
76 |
env->sni_context_string()).ToLocalChecked(); |
|
2835 |
19 |
Local<FunctionTemplate> cons = env->secure_context_constructor_template(); |
|
2836 |
|||
2837 |
// Not an object, probably undefined or null |
||
2838 |
✓✓ | 19 |
if (!ctx->IsObject()) |
2839 |
8 |
goto fire_cb; |
|
2840 |
|||
2841 |
✓✓ | 11 |
if (cons->HasInstance(ctx)) { |
2842 |
SecureContext* sc; |
||
2843 |
✗✓ | 10 |
ASSIGN_OR_RETURN_UNWRAP(&sc, ctx.As<Object>()); |
2844 |
9 |
w->sni_context_.Reset(env->isolate(), ctx); |
|
2845 |
|||
2846 |
int rv; |
||
2847 |
|||
2848 |
// NOTE: reference count is not increased by this API methods |
||
2849 |
9 |
X509* x509 = SSL_CTX_get0_certificate(sc->ctx_.get()); |
|
2850 |
9 |
EVP_PKEY* pkey = SSL_CTX_get0_privatekey(sc->ctx_.get()); |
|
2851 |
STACK_OF(X509)* chain; |
||
2852 |
|||
2853 |
9 |
rv = SSL_CTX_get0_chain_certs(sc->ctx_.get(), &chain); |
|
2854 |
✓✗ | 9 |
if (rv) |
2855 |
9 |
rv = SSL_use_certificate(w->ssl_.get(), x509); |
|
2856 |
✓✓ | 9 |
if (rv) |
2857 |
8 |
rv = SSL_use_PrivateKey(w->ssl_.get(), pkey); |
|
2858 |
✓✓✓✓ |
9 |
if (rv && chain != nullptr) |
2859 |
1 |
rv = SSL_set1_chain(w->ssl_.get(), chain); |
|
2860 |
✓✓ | 9 |
if (rv) |
2861 |
8 |
rv = w->SetCACerts(sc); |
|
2862 |
✓✓ | 9 |
if (!rv) { |
2863 |
// Not clear why sometimes we throw error, and sometimes we call |
||
2864 |
// onerror(). Both cause .destroy(), but onerror does a bit more. |
||
2865 |
1 |
unsigned long err = ERR_get_error(); // NOLINT(runtime/int) |
|
2866 |
✗✓ | 1 |
if (!err) |
2867 |
return env->ThrowError("CertCbDone"); |
||
2868 |
1 |
return ThrowCryptoError(env, err); |
|
2869 |
} |
||
2870 |
} else { |
||
2871 |
// Failure: incorrect SNI context object |
||
2872 |
2 |
Local<Value> err = Exception::TypeError(env->sni_context_err_string()); |
|
2873 |
2 |
w->MakeCallback(env->onerror_string(), 1, &err); |
|
2874 |
2 |
return; |
|
2875 |
} |
||
2876 |
|||
2877 |
fire_cb: |
||
2878 |
CertCb cb; |
||
2879 |
void* arg; |
||
2880 |
|||
2881 |
16 |
cb = w->cert_cb_; |
|
2882 |
16 |
arg = w->cert_cb_arg_; |
|
2883 |
|||
2884 |
16 |
w->cert_cb_running_ = false; |
|
2885 |
16 |
w->cert_cb_ = nullptr; |
|
2886 |
16 |
w->cert_cb_arg_ = nullptr; |
|
2887 |
|||
2888 |
16 |
cb(arg); |
|
2889 |
} |
||
2890 |
|||
2891 |
|||
2892 |
template <class Base> |
||
2893 |
24329 |
void SSLWrap<Base>::DestroySSL() { |
|
2894 |
✓✓ | 24329 |
if (!ssl_) |
2895 |
36441 |
return; |
|
2896 |
|||
2897 |
12217 |
env_->isolate()->AdjustAmountOfExternalAllocatedMemory(-kExternalSize); |
|
2898 |
12217 |
ssl_.reset(); |
|
2899 |
} |
||
2900 |
|||
2901 |
|||
2902 |
template <class Base> |
||
2903 |
void SSLWrap<Base>::SetSNIContext(SecureContext* sc) { |
||
2904 |
ConfigureSecureContext(sc); |
||
2905 |
CHECK_EQ(SSL_set_SSL_CTX(ssl_.get(), sc->ctx_.get()), sc->ctx_.get()); |
||
2906 |
|||
2907 |
SetCACerts(sc); |
||
2908 |
} |
||
2909 |
|||
2910 |
|||
2911 |
template <class Base> |
||
2912 |
8 |
int SSLWrap<Base>::SetCACerts(SecureContext* sc) { |
|
2913 |
8 |
int err = SSL_set1_verify_cert_store(ssl_.get(), |
|
2914 |
SSL_CTX_get_cert_store(sc->ctx_.get())); |
||
2915 |
✗✓ | 8 |
if (err != 1) |
2916 |
return err; |
||
2917 |
|||
2918 |
STACK_OF(X509_NAME)* list = SSL_dup_CA_list( |
||
2919 |
8 |
SSL_CTX_get_client_CA_list(sc->ctx_.get())); |
|
2920 |
|||
2921 |
// NOTE: `SSL_set_client_CA_list` takes the ownership of `list` |
||
2922 |
8 |
SSL_set_client_CA_list(ssl_.get(), list); |
|
2923 |
8 |
return 1; |
|
2924 |
} |
||
2925 |
|||
2926 |
2172 |
int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) { |
|
2927 |
// From https://www.openssl.org/docs/man1.1.1/man3/SSL_verify_cb: |
||
2928 |
// |
||
2929 |
// If VerifyCallback returns 1, the verification process is continued. If |
||
2930 |
// VerifyCallback always returns 1, the TLS/SSL handshake will not be |
||
2931 |
// terminated with respect to verification failures and the connection will |
||
2932 |
// be established. The calling process can however retrieve the error code |
||
2933 |
// of the last verification error using SSL_get_verify_result(3) or by |
||
2934 |
// maintaining its own error storage managed by VerifyCallback. |
||
2935 |
// |
||
2936 |
// Since we cannot perform I/O quickly enough with X509_STORE_CTX_ APIs in |
||
2937 |
// this callback, we ignore all preverify_ok errors and let the handshake |
||
2938 |
// continue. It is imperative that the user use Connection::VerifyError after |
||
2939 |
// the 'secure' callback has been made. |
||
2940 |
2172 |
return 1; |
|
2941 |
} |
||
2942 |
|||
2943 |
3377 |
static bool IsSupportedAuthenticatedMode(const EVP_CIPHER* cipher) { |
|
2944 |
3377 |
const int mode = EVP_CIPHER_mode(cipher); |
|
2945 |
// Check `chacha20-poly1305` separately, it is also an AEAD cipher, |
||
2946 |
// but its mode is 0 which doesn't indicate |
||
2947 |
✓✓ | 6707 |
return EVP_CIPHER_nid(cipher) == NID_chacha20_poly1305 || |
2948 |
✓✓ | 6116 |
mode == EVP_CIPH_CCM_MODE || |
2949 |
✓✓✓✓ |
7502 |
mode == EVP_CIPH_GCM_MODE || |
2950 |
4716 |
IS_OCB_MODE(mode); |
|
2951 |
} |
||
2952 |
|||
2953 |
1471 |
static bool IsSupportedAuthenticatedMode(const EVP_CIPHER_CTX* ctx) { |
|
2954 |
1471 |
const EVP_CIPHER* cipher = EVP_CIPHER_CTX_cipher(ctx); |
|
2955 |
1471 |
return IsSupportedAuthenticatedMode(cipher); |
|
2956 |
} |
||
2957 |
|||
2958 |
enum class ParseKeyResult { |
||
2959 |
kParseKeyOk, |
||
2960 |
kParseKeyNotRecognized, |
||
2961 |
kParseKeyNeedPassphrase, |
||
2962 |
kParseKeyFailed |
||
2963 |
}; |
||
2964 |
|||
2965 |
2821 |
static ParseKeyResult TryParsePublicKey( |
|
2966 |
EVPKeyPointer* pkey, |
||
2967 |
const BIOPointer& bp, |
||
2968 |
const char* name, |
||
2969 |
// NOLINTNEXTLINE(runtime/int) |
||
2970 |
const std::function<EVP_PKEY*(const unsigned char** p, long l)>& parse) { |
||
2971 |
unsigned char* der_data; |
||
2972 |
long der_len; // NOLINT(runtime/int) |
||
2973 |
|||
2974 |
// This skips surrounding data and decodes PEM to DER. |
||
2975 |
{ |
||
2976 |
2821 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
|
2977 |
✓✓ | 2821 |
if (PEM_bytes_read_bio(&der_data, &der_len, nullptr, name, |
2978 |
2821 |
bp.get(), nullptr, nullptr) != 1) |
|
2979 |
✓✓ | 1956 |
return ParseKeyResult::kParseKeyNotRecognized; |
2980 |
} |
||
2981 |
|||
2982 |
// OpenSSL might modify the pointer, so we need to make a copy before parsing. |
||
2983 |
865 |
const unsigned char* p = der_data; |
|
2984 |
865 |
pkey->reset(parse(&p, der_len)); |
|
2985 |
865 |
OPENSSL_clear_free(der_data, der_len); |
|
2986 |
|||
2987 |
return *pkey ? ParseKeyResult::kParseKeyOk : |
||
2988 |
✓✗ | 865 |
ParseKeyResult::kParseKeyFailed; |
2989 |
} |
||
2990 |
|||
2991 |
1024 |
static ParseKeyResult ParsePublicKeyPEM(EVPKeyPointer* pkey, |
|
2992 |
const char* key_pem, |
||
2993 |
int key_pem_len) { |
||
2994 |
1024 |
BIOPointer bp(BIO_new_mem_buf(const_cast<char*>(key_pem), key_pem_len)); |
|
2995 |
✗✓ | 1024 |
if (!bp) |
2996 |
return ParseKeyResult::kParseKeyFailed; |
||
2997 |
|||
2998 |
ParseKeyResult ret; |
||
2999 |
|||
3000 |
// Try parsing as a SubjectPublicKeyInfo first. |
||
3001 |
ret = TryParsePublicKey(pkey, bp, "PUBLIC KEY", |
||
3002 |
118 |
[](const unsigned char** p, long l) { // NOLINT(runtime/int) |
|
3003 |
return d2i_PUBKEY(nullptr, p, l); |
||
3004 |
1142 |
}); |
|
3005 |
✓✓ | 1024 |
if (ret != ParseKeyResult::kParseKeyNotRecognized) |
3006 |
118 |
return ret; |
|
3007 |
|||
3008 |
// Maybe it is PKCS#1. |
||
3009 |
✗✓ | 906 |
CHECK(BIO_reset(bp.get())); |
3010 |
ret = TryParsePublicKey(pkey, bp, "RSA PUBLIC KEY", |
||
3011 |
15 |
[](const unsigned char** p, long l) { // NOLINT(runtime/int) |
|
3012 |
return d2i_PublicKey(EVP_PKEY_RSA, nullptr, p, l); |
||
3013 |
921 |
}); |
|
3014 |
✓✓ | 906 |
if (ret != ParseKeyResult::kParseKeyNotRecognized) |
3015 |
15 |
return ret; |
|
3016 |
|||
3017 |
// X.509 fallback. |
||
3018 |
✗✓ | 891 |
CHECK(BIO_reset(bp.get())); |
3019 |
return TryParsePublicKey(pkey, bp, "CERTIFICATE", |
||
3020 |
732 |
[](const unsigned char** p, long l) { // NOLINT(runtime/int) |
|
3021 |
732 |
X509Pointer x509(d2i_X509(nullptr, p, l)); |
|
3022 |
✓✗ | 1464 |
return x509 ? X509_get_pubkey(x509.get()) : nullptr; |
3023 |
1623 |
}); |
|
3024 |
} |
||
3025 |
|||
3026 |
21 |
static ParseKeyResult ParsePublicKey(EVPKeyPointer* pkey, |
|
3027 |
const PublicKeyEncodingConfig& config, |
||
3028 |
const char* key, |
||
3029 |
size_t key_len) { |
||
3030 |
✗✓ | 21 |
if (config.format_ == kKeyFormatPEM) { |
3031 |
return ParsePublicKeyPEM(pkey, key, key_len); |
||
3032 |
} else { |
||
3033 |
✗✓ | 21 |
CHECK_EQ(config.format_, kKeyFormatDER); |
3034 |
|||
3035 |
21 |
const unsigned char* p = reinterpret_cast<const unsigned char*>(key); |
|
3036 |
✓✗ | 42 |
if (config.type_.ToChecked() == kKeyEncodingPKCS1) { |
3037 |
21 |
pkey->reset(d2i_PublicKey(EVP_PKEY_RSA, nullptr, &p, key_len)); |
|
3038 |
} else { |
||
3039 |
CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSPKI); |
||
3040 |
pkey->reset(d2i_PUBKEY(nullptr, &p, key_len)); |
||
3041 |
} |
||
3042 |
|||
3043 |
return *pkey ? ParseKeyResult::kParseKeyOk : |
||
3044 |
✓✗ | 21 |
ParseKeyResult::kParseKeyFailed; |
3045 |
} |
||
3046 |
} |
||
3047 |
|||
3048 |
46 |
static inline Local<Value> BIOToStringOrBuffer(Environment* env, |
|
3049 |
BIO* bio, |
||
3050 |
PKFormatType format) { |
||
3051 |
BUF_MEM* bptr; |
||
3052 |
46 |
BIO_get_mem_ptr(bio, &bptr); |
|
3053 |
✓✓ | 46 |
if (format == kKeyFormatPEM) { |
3054 |
// PEM is an ASCII format, so we will return it as a string. |
||
3055 |
return String::NewFromUtf8(env->isolate(), bptr->data, |
||
3056 |
NewStringType::kNormal, |
||
3057 |
74 |
bptr->length).ToLocalChecked(); |
|
3058 |
} else { |
||
3059 |
✗✓ | 9 |
CHECK_EQ(format, kKeyFormatDER); |
3060 |
// DER is binary, return it as a buffer. |
||
3061 |
18 |
return Buffer::Copy(env, bptr->data, bptr->length).ToLocalChecked(); |
|
3062 |
} |
||
3063 |
} |
||
3064 |
|||
3065 |
25 |
static bool WritePublicKeyInner(EVP_PKEY* pkey, |
|
3066 |
const BIOPointer& bio, |
||
3067 |
const PublicKeyEncodingConfig& config) { |
||
3068 |
✓✓ | 50 |
if (config.type_.ToChecked() == kKeyEncodingPKCS1) { |
3069 |
// PKCS#1 is only valid for RSA keys. |
||
3070 |
✗✓ | 8 |
CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_RSA); |
3071 |
8 |
RSAPointer rsa(EVP_PKEY_get1_RSA(pkey)); |
|
3072 |
✓✓ | 8 |
if (config.format_ == kKeyFormatPEM) { |
3073 |
// Encode PKCS#1 as PEM. |
||
3074 |
3 |
return PEM_write_bio_RSAPublicKey(bio.get(), rsa.get()) == 1; |
|
3075 |
} else { |
||
3076 |
// Encode PKCS#1 as DER. |
||
3077 |
✗✓ | 5 |
CHECK_EQ(config.format_, kKeyFormatDER); |
3078 |
5 |
return i2d_RSAPublicKey_bio(bio.get(), rsa.get()) == 1; |
|
3079 |
8 |
} |
|
3080 |
} else { |
||
3081 |
✗✓ | 34 |
CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSPKI); |
3082 |
✓✗ | 17 |
if (config.format_ == kKeyFormatPEM) { |
3083 |
// Encode SPKI as PEM. |
||
3084 |
17 |
return PEM_write_bio_PUBKEY(bio.get(), pkey) == 1; |
|
3085 |
} else { |
||
3086 |
// Encode SPKI as DER. |
||
3087 |
CHECK_EQ(config.format_, kKeyFormatDER); |
||
3088 |
return i2d_PUBKEY_bio(bio.get(), pkey) == 1; |
||
3089 |
} |
||
3090 |
} |
||
3091 |
} |
||
3092 |
|||
3093 |
25 |
static MaybeLocal<Value> WritePublicKey(Environment* env, |
|
3094 |
EVP_PKEY* pkey, |
||
3095 |
const PublicKeyEncodingConfig& config) { |
||
3096 |
25 |
BIOPointer bio(BIO_new(BIO_s_mem())); |
|
3097 |
✗✓ | 25 |
CHECK(bio); |
3098 |
|||
3099 |
✗✓ | 25 |
if (!WritePublicKeyInner(pkey, bio, config)) { |
3100 |
ThrowCryptoError(env, ERR_get_error(), "Failed to encode public key"); |
||
3101 |
return MaybeLocal<Value>(); |
||
3102 |
} |
||
3103 |
50 |
return BIOToStringOrBuffer(env, bio.get(), config.format_); |
|
3104 |
} |
||
3105 |
|||
3106 |
56 |
static bool IsASN1Sequence(const unsigned char* data, size_t size, |
|
3107 |
size_t* data_offset, size_t* data_size) { |
||
3108 |
✓✗✗✓ |
56 |
if (size < 2 || data[0] != 0x30) |
3109 |
return false; |
||
3110 |
|||
3111 |
✓✓ | 56 |
if (data[1] & 0x80) { |
3112 |
// Long form. |
||
3113 |
36 |
size_t n_bytes = data[1] & ~0x80; |
|
3114 |
✓✗✗✓ |
36 |
if (n_bytes + 2 > size || n_bytes > sizeof(size_t)) |
3115 |
return false; |
||
3116 |
36 |
size_t length = 0; |
|
3117 |
✓✓ | 108 |
for (size_t i = 0; i < n_bytes; i++) |
3118 |
72 |
length = (length << 8) | data[i + 2]; |
|
3119 |
36 |
*data_offset = 2 + n_bytes; |
|
3120 |
36 |
*data_size = std::min(size - 2 - n_bytes, length); |
|
3121 |
} else { |
||
3122 |
// Short form. |
||
3123 |
20 |
*data_offset = 2; |
|
3124 |
20 |
*data_size = std::min<size_t>(size - 2, data[1]); |
|
3125 |
} |
||
3126 |
|||
3127 |
56 |
return true; |
|
3128 |
} |
||
3129 |
|||
3130 |
30 |
static bool IsRSAPrivateKey(const unsigned char* data, size_t size) { |
|
3131 |
// Both RSAPrivateKey and RSAPublicKey structures start with a SEQUENCE. |
||
3132 |
size_t offset, len; |
||
3133 |
✗✓ | 30 |
if (!IsASN1Sequence(data, size, &offset, &len)) |
3134 |
return false; |
||
3135 |
|||
3136 |
// An RSAPrivateKey sequence always starts with a single-byte integer whose |
||
3137 |
// value is either 0 or 1, whereas an RSAPublicKey starts with the modulus |
||
3138 |
// (which is the product of two primes and therefore at least 4), so we can |
||
3139 |
// decide the type of the structure based on the first three bytes of the |
||
3140 |
// sequence. |
||
3141 |
✓✗ | 60 |
return len >= 3 && |
3142 |
✓✓ | 60 |
data[offset] == 2 && |
3143 |
✓✗✓✗ |
69 |
data[offset + 1] == 1 && |
3144 |
39 |
!(data[offset + 2] & 0xfe); |
|
3145 |
} |
||
3146 |
|||
3147 |
26 |
static bool IsEncryptedPrivateKeyInfo(const unsigned char* data, size_t size) { |
|
3148 |
// Both PrivateKeyInfo and EncryptedPrivateKeyInfo start with a SEQUENCE. |
||
3149 |
size_t offset, len; |
||
3150 |
✗✓ | 26 |
if (!IsASN1Sequence(data, size, &offset, &len)) |
3151 |
return false; |
||
3152 |
|||
3153 |
// A PrivateKeyInfo sequence always starts with an integer whereas an |
||
3154 |
// EncryptedPrivateKeyInfo starts with an AlgorithmIdentifier. |
||
3155 |
✓✗✓✓ |
52 |
return len >= 1 && |
3156 |
52 |
data[offset] != 2; |
|
3157 |
} |
||
3158 |
|||
3159 |
355 |
static ParseKeyResult ParsePrivateKey(EVPKeyPointer* pkey, |
|
3160 |
const PrivateKeyEncodingConfig& config, |
||
3161 |
const char* key, |
||
3162 |
size_t key_len) { |
||
3163 |
// OpenSSL needs a non-const pointer, that's why the const_cast is required. |
||
3164 |
355 |
char* const passphrase = const_cast<char*>(config.passphrase_.get()); |
|
3165 |
|||
3166 |
✓✓ | 355 |
if (config.format_ == kKeyFormatPEM) { |
3167 |
320 |
BIOPointer bio(BIO_new_mem_buf(key, key_len)); |
|
3168 |
✓✓ | 320 |
if (!bio) |
3169 |
1 |
return ParseKeyResult::kParseKeyFailed; |
|
3170 |
|||
3171 |
pkey->reset(PEM_read_bio_PrivateKey(bio.get(), |
||
3172 |
nullptr, |
||
3173 |
PasswordCallback, |
||
3174 |
✓✓ | 319 |
passphrase)); |
3175 |
} else { |
||
3176 |
✗✓ | 35 |
CHECK_EQ(config.format_, kKeyFormatDER); |
3177 |
|||
3178 |
✓✓ | 70 |
if (config.type_.ToChecked() == kKeyEncodingPKCS1) { |
3179 |
9 |
const unsigned char* p = reinterpret_cast<const unsigned char*>(key); |
|
3180 |
9 |
pkey->reset(d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &p, key_len)); |
|
3181 |
✓✗ | 52 |
} else if (config.type_.ToChecked() == kKeyEncodingPKCS8) { |
3182 |
26 |
BIOPointer bio(BIO_new_mem_buf(key, key_len)); |
|
3183 |
✗✓ | 26 |
if (!bio) |
3184 |
return ParseKeyResult::kParseKeyFailed; |
||
3185 |
|||
3186 |
✓✓ | 26 |
if (IsEncryptedPrivateKeyInfo( |
3187 |
reinterpret_cast<const unsigned char*>(key), key_len)) { |
||
3188 |
pkey->reset(d2i_PKCS8PrivateKey_bio(bio.get(), |
||
3189 |
nullptr, |
||
3190 |
PasswordCallback, |
||
3191 |
17 |
passphrase)); |
|
3192 |
} else { |
||
3193 |
9 |
PKCS8Pointer p8inf(d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), nullptr)); |
|
3194 |
✓✗ | 9 |
if (p8inf) |
3195 |
✓✗ | 9 |
pkey->reset(EVP_PKCS82PKEY(p8inf.get())); |
3196 |
26 |
} |
|
3197 |
} else { |
||
3198 |
CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSEC1); |
||
3199 |
const unsigned char* p = reinterpret_cast<const unsigned char*>(key); |
||
3200 |
pkey->reset(d2i_PrivateKey(EVP_PKEY_EC, nullptr, &p, key_len)); |
||
3201 |
} |
||
3202 |
} |
||
3203 |
|||
3204 |
// OpenSSL can fail to parse the key but still return a non-null pointer. |
||
3205 |
354 |
unsigned long err = ERR_peek_error(); // NOLINT(runtime/int) |
|
3206 |
✓✓ | 354 |
if (err != 0) |
3207 |
17 |
pkey->reset(); |
|
3208 |
|||
3209 |
✓✓ | 354 |
if (*pkey) |
3210 |
337 |
return ParseKeyResult::kParseKeyOk; |
|
3211 |
✓✓✓✓ |
27 |
if (ERR_GET_LIB(err) == ERR_LIB_PEM && |
3212 |
10 |
ERR_GET_REASON(err) == PEM_R_BAD_PASSWORD_READ) { |
|
3213 |
✓✓ | 9 |
if (config.passphrase_.get() == nullptr) |
3214 |
8 |
return ParseKeyResult::kParseKeyNeedPassphrase; |
|
3215 |
} |
||
3216 |
9 |
return ParseKeyResult::kParseKeyFailed; |
|
3217 |
} |
||
3218 |
|||
3219 |
2364 |
ByteSource::ByteSource(ByteSource&& other) |
|
3220 |
: data_(other.data_), |
||
3221 |
allocated_data_(other.allocated_data_), |
||
3222 |
2364 |
size_(other.size_) { |
|
3223 |
2364 |
other.allocated_data_ = nullptr; |
|
3224 |
2364 |
} |
|
3225 |
|||
3226 |
6289 |
ByteSource::~ByteSource() { |
|
3227 |
6289 |
OPENSSL_clear_free(allocated_data_, size_); |
|
3228 |
6289 |
} |
|
3229 |
|||
3230 |
85 |
ByteSource& ByteSource::operator=(ByteSource&& other) { |
|
3231 |
✓✗ | 85 |
if (&other != this) { |
3232 |
85 |
OPENSSL_clear_free(allocated_data_, size_); |
|
3233 |
85 |
data_ = other.data_; |
|
3234 |
85 |
allocated_data_ = other.allocated_data_; |
|
3235 |
85 |
other.allocated_data_ = nullptr; |
|
3236 |
85 |
size_ = other.size_; |
|
3237 |
} |
||
3238 |
85 |
return *this; |
|
3239 |
} |
||
3240 |
|||
3241 |
3142 |
const char* ByteSource::get() const { |
|
3242 |
3142 |
return data_; |
|
3243 |
} |
||
3244 |
|||
3245 |
2778 |
size_t ByteSource::size() const { |
|
3246 |
2778 |
return size_; |
|
3247 |
} |
||
3248 |
|||
3249 |
2555 |
ByteSource ByteSource::FromStringOrBuffer(Environment* env, |
|
3250 |
Local<Value> value) { |
||
3251 |
2555 |
return Buffer::HasInstance(value) ? FromBuffer(value) |
|
3252 |
✓✓ | 2929 |
: FromString(env, value.As<String>()); |
3253 |
} |
||
3254 |
|||
3255 |
448 |
ByteSource ByteSource::FromString(Environment* env, Local<String> str, |
|
3256 |
bool ntc) { |
||
3257 |
✗✓ | 896 |
CHECK(str->IsString()); |
3258 |
896 |
size_t size = str->Utf8Length(env->isolate()); |
|
3259 |
✓✓ | 448 |
size_t alloc_size = ntc ? size + 1 : size; |
3260 |
448 |
char* data = MallocOpenSSL<char>(alloc_size); |
|
3261 |
448 |
int opts = String::NO_OPTIONS; |
|
3262 |
✓✓ | 448 |
if (!ntc) opts |= String::NO_NULL_TERMINATION; |
3263 |
896 |
str->WriteUtf8(env->isolate(), data, alloc_size, nullptr, opts); |
|
3264 |
448 |
return Allocated(data, size); |
|
3265 |
} |
||
3266 |
|||
3267 |
2192 |
ByteSource ByteSource::FromBuffer(Local<Value> buffer, bool ntc) { |
|
3268 |
✗✓ | 2192 |
CHECK(buffer->IsArrayBufferView()); |
3269 |
2192 |
Local<ArrayBufferView> abv = buffer.As<ArrayBufferView>(); |
|
3270 |
2192 |
size_t size = abv->ByteLength(); |
|
3271 |
✓✓ | 2192 |
if (ntc) { |
3272 |
11 |
char* data = MallocOpenSSL<char>(size + 1); |
|
3273 |
11 |
abv->CopyContents(data, size); |
|
3274 |
11 |
data[size] = 0; |
|
3275 |
11 |
return Allocated(data, size); |
|
3276 |
} |
||
3277 |
2181 |
return Foreign(Buffer::Data(buffer), size); |
|
3278 |
} |
||
3279 |
|||
3280 |
85 |
ByteSource ByteSource::NullTerminatedCopy(Environment* env, |
|
3281 |
Local<Value> value) { |
||
3282 |
85 |
return Buffer::HasInstance(value) ? FromBuffer(value, true) |
|
3283 |
✓✓ | 159 |
: FromString(env, value.As<String>(), true); |
3284 |
} |
||
3285 |
|||
3286 |
14 |
ByteSource ByteSource::FromSymmetricKeyObject(Local<Value> handle) { |
|
3287 |
✗✓ | 14 |
CHECK(handle->IsObject()); |
3288 |
14 |
KeyObject* key = Unwrap<KeyObject>(handle.As<Object>()); |
|
3289 |
✗✓ | 14 |
CHECK(key); |
3290 |
14 |
return Foreign(key->GetSymmetricKey(), key->GetSymmetricKeySize()); |
|
3291 |
} |
||
3292 |
|||
3293 |
2654 |
ByteSource::ByteSource(const char* data, char* allocated_data, size_t size) |
|
3294 |
: data_(data), |
||
3295 |
allocated_data_(allocated_data), |
||
3296 |
2654 |
size_(size) {} |
|
3297 |
|||
3298 |
459 |
ByteSource ByteSource::Allocated(char* data, size_t size) { |
|
3299 |
459 |
return ByteSource(data, data, size); |
|
3300 |
} |
||
3301 |
|||
3302 |
2195 |
ByteSource ByteSource::Foreign(const char* data, size_t size) { |
|
3303 |
2195 |
return ByteSource(data, nullptr, size); |
|
3304 |
} |
||
3305 |
|||
3306 |
enum KeyEncodingContext { |
||
3307 |
kKeyContextInput, |
||
3308 |
kKeyContextExport, |
||
3309 |
kKeyContextGenerate |
||
3310 |
}; |
||
3311 |
|||
3312 |
1303 |
static void GetKeyFormatAndTypeFromJs( |
|
3313 |
AsymmetricKeyEncodingConfig* config, |
||
3314 |
const FunctionCallbackInfo<Value>& args, |
||
3315 |
unsigned int* offset, |
||
3316 |
KeyEncodingContext context) { |
||
3317 |
// During key pair generation, it is possible not to specify a key encoding, |
||
3318 |
// which will lead to a key object being returned. |
||
3319 |
✓✓ | 5212 |
if (args[*offset]->IsUndefined()) { |
3320 |
✗✓ | 14 |
CHECK_EQ(context, kKeyContextGenerate); |
3321 |
✗✓ | 56 |
CHECK(args[*offset + 1]->IsUndefined()); |
3322 |
14 |
config->output_key_object_ = true; |
|
3323 |
} else { |
||
3324 |
1289 |
config->output_key_object_ = false; |
|
3325 |
|||
3326 |
✗✓ | 3867 |
CHECK(args[*offset]->IsInt32()); |
3327 |
config->format_ = static_cast<PKFormatType>( |
||
3328 |
5156 |
args[*offset].As<Int32>()->Value()); |
|
3329 |
|||
3330 |
✓✓ | 3867 |
if (args[*offset + 1]->IsInt32()) { |
3331 |
config->type_ = Just<PKEncodingType>(static_cast<PKEncodingType>( |
||
3332 |
416 |
args[*offset + 1].As<Int32>()->Value())); |
|
3333 |
} else { |
||
3334 |
✓✗✗✓ ✗✓ |
1185 |
CHECK(context == kKeyContextInput && config->format_ == kKeyFormatPEM); |
3335 |
✗✓ | 4740 |
CHECK(args[*offset + 1]->IsNullOrUndefined()); |
3336 |
1185 |
config->type_ = Nothing<PKEncodingType>(); |
|
3337 |
} |
||
3338 |
} |
||
3339 |
|||
3340 |
1303 |
*offset += 2; |
|
3341 |
1303 |
} |
|
3342 |
|||
3343 |
33 |
static PublicKeyEncodingConfig GetPublicKeyEncodingFromJs( |
|
3344 |
const FunctionCallbackInfo<Value>& args, |
||
3345 |
unsigned int* offset, |
||
3346 |
KeyEncodingContext context) { |
||
3347 |
33 |
PublicKeyEncodingConfig result; |
|
3348 |
33 |
GetKeyFormatAndTypeFromJs(&result, args, offset, context); |
|
3349 |
33 |
return result; |
|
3350 |
} |
||
3351 |
|||
3352 |
1241 |
static inline ManagedEVPPKey GetParsedKey(Environment* env, |
|
3353 |
EVPKeyPointer&& pkey, |
||
3354 |
ParseKeyResult ret, |
||
3355 |
const char* default_msg) { |
||
3356 |
✓✓✓ | 1241 |
switch (ret) { |
3357 |
case ParseKeyResult::kParseKeyOk: |
||
3358 |
✗✓ | 1223 |
CHECK(pkey); |
3359 |
1223 |
break; |
|
3360 |
case ParseKeyResult::kParseKeyNeedPassphrase: |
||
3361 |
THROW_ERR_MISSING_PASSPHRASE(env, |
||
3362 |
8 |
"Passphrase required for encrypted key"); |
|
3363 |
8 |
break; |
|
3364 |
default: |
||
3365 |
10 |
ThrowCryptoError(env, ERR_get_error(), default_msg); |
|
3366 |
} |
||
3367 |
|||
3368 |
1241 |
return ManagedEVPPKey(std::move(pkey)); |
|
3369 |
} |
||
3370 |
|||
3371 |
1270 |
static NonCopyableMaybe<PrivateKeyEncodingConfig> GetPrivateKeyEncodingFromJs( |
|
3372 |
const FunctionCallbackInfo<Value>& args, |
||
3373 |
unsigned int* offset, |
||
3374 |
KeyEncodingContext context) { |
||
3375 |
1270 |
Environment* env = Environment::GetCurrent(args); |
|
3376 |
|||
3377 |
1270 |
PrivateKeyEncodingConfig result; |
|
3378 |
1270 |
GetKeyFormatAndTypeFromJs(&result, args, offset, context); |
|
3379 |
|||
3380 |
✓✓ | 1270 |
if (result.output_key_object_) { |
3381 |
✓✗ | 7 |
if (context != kKeyContextInput) |
3382 |
7 |
(*offset)++; |
|
3383 |
} else { |
||
3384 |
1263 |
bool needs_passphrase = false; |
|
3385 |
✓✓ | 1263 |
if (context != kKeyContextInput) { |
3386 |
✓✓ | 88 |
if (args[*offset]->IsString()) { |
3387 |
String::Utf8Value cipher_name(env->isolate(), |
||
3388 |
24 |
args[*offset].As<String>()); |
|
3389 |
8 |
result.cipher_ = EVP_get_cipherbyname(*cipher_name); |
|
3390 |
✓✓ | 8 |
if (result.cipher_ == nullptr) { |
3391 |
1 |
env->ThrowError("Unknown cipher"); |
|
3392 |
1 |
return NonCopyableMaybe<PrivateKeyEncodingConfig>(); |
|
3393 |
} |
||
3394 |
✓✓ | 7 |
needs_passphrase = true; |
3395 |
} else { |
||
3396 |
✗✓ | 56 |
CHECK(args[*offset]->IsNullOrUndefined()); |
3397 |
14 |
result.cipher_ = nullptr; |
|
3398 |
} |
||
3399 |
21 |
(*offset)++; |
|
3400 |
} |
||
3401 |
|||
3402 |
✓✓✓✓ ✓✗✓✓ |
6236 |
if (args[*offset]->IsString() || Buffer::HasInstance(args[*offset])) { |
3403 |
✓✓✗✓ ✗✓ |
85 |
CHECK_IMPLIES(context != kKeyContextInput, result.cipher_ != nullptr); |
3404 |
|||
3405 |
170 |
result.passphrase_ = ByteSource::NullTerminatedCopy(env, args[*offset]); |
|
3406 |
} else { |
||
3407 |
✓✗✗✓ ✓✗✗✓ |
4708 |
CHECK(args[*offset]->IsNullOrUndefined() && !needs_passphrase); |
3408 |
} |
||
3409 |
} |
||
3410 |
|||
3411 |
1269 |
(*offset)++; |
|
3412 |
1269 |
return NonCopyableMaybe<PrivateKeyEncodingConfig>(std::move(result)); |
|
3413 |
} |
||
3414 |
|||
3415 |
202 |
static ManagedEVPPKey GetPrivateKeyFromJs( |
|
3416 |
const FunctionCallbackInfo<Value>& args, |
||
3417 |
unsigned int* offset, |
||
3418 |
bool allow_key_object) { |
||
3419 |
✓✓✓✓ ✓✗✓✓ |
934 |
if (args[*offset]->IsString() || Buffer::HasInstance(args[*offset])) { |
3420 |
169 |
Environment* env = Environment::GetCurrent(args); |
|
3421 |
338 |
ByteSource key = ByteSource::FromStringOrBuffer(env, args[(*offset)++]); |
|
3422 |
NonCopyableMaybe<PrivateKeyEncodingConfig> config = |
||
3423 |
338 |
GetPrivateKeyEncodingFromJs(args, offset, kKeyContextInput); |
|
3424 |
✗✓ | 169 |
if (config.IsEmpty()) |
3425 |
return ManagedEVPPKey(); |
||
3426 |
|||
3427 |
338 |
EVPKeyPointer pkey; |
|
3428 |
ParseKeyResult ret = |
||
3429 |
169 |
ParsePrivateKey(&pkey, config.Release(), key.get(), key.size()); |
|
3430 |
169 |
return GetParsedKey(env, std::move(pkey), ret, |
|
3431 |
338 |
"Failed to read private key"); |
|
3432 |
} else { |
||
3433 |
✓✗✗✓ ✓✗✗✓ |
99 |