GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
#include "crypto/crypto_context.h" |
||
2 |
#include "crypto/crypto_bio.h" |
||
3 |
#include "crypto/crypto_common.h" |
||
4 |
#include "crypto/crypto_util.h" |
||
5 |
#include "base_object-inl.h" |
||
6 |
#include "env-inl.h" |
||
7 |
#include "memory_tracker-inl.h" |
||
8 |
#include "node.h" |
||
9 |
#include "node_buffer.h" |
||
10 |
#include "node_options.h" |
||
11 |
#include "util.h" |
||
12 |
#include "v8.h" |
||
13 |
|||
14 |
#include <openssl/x509.h> |
||
15 |
#include <openssl/pkcs12.h> |
||
16 |
#include <openssl/rand.h> |
||
17 |
#ifndef OPENSSL_NO_ENGINE |
||
18 |
#include <openssl/engine.h> |
||
19 |
#endif // !OPENSSL_NO_ENGINE |
||
20 |
|||
21 |
namespace node { |
||
22 |
|||
23 |
using v8::Array; |
||
24 |
using v8::ArrayBufferView; |
||
25 |
using v8::Context; |
||
26 |
using v8::DontDelete; |
||
27 |
using v8::Exception; |
||
28 |
using v8::External; |
||
29 |
using v8::FunctionCallbackInfo; |
||
30 |
using v8::FunctionTemplate; |
||
31 |
using v8::HandleScope; |
||
32 |
using v8::Int32; |
||
33 |
using v8::Integer; |
||
34 |
using v8::Local; |
||
35 |
using v8::Object; |
||
36 |
using v8::PropertyAttribute; |
||
37 |
using v8::ReadOnly; |
||
38 |
using v8::Signature; |
||
39 |
using v8::String; |
||
40 |
using v8::Value; |
||
41 |
|||
42 |
namespace crypto { |
||
43 |
static const char* const root_certs[] = { |
||
44 |
#include "node_root_certs.h" // NOLINT(build/include_order) |
||
45 |
}; |
||
46 |
|||
47 |
static const char system_cert_path[] = NODE_OPENSSL_SYSTEM_CERT_PATH; |
||
48 |
|||
49 |
static X509_STORE* root_cert_store; |
||
50 |
|||
51 |
static bool extra_root_certs_loaded = false; |
||
52 |
|||
53 |
// Takes a string or buffer and loads it into a BIO. |
||
54 |
// Caller responsible for BIO_free_all-ing the returned object. |
||
55 |
2549 |
BIOPointer LoadBIO(Environment* env, Local<Value> v) { |
|
56 |
5098 |
HandleScope scope(env->isolate()); |
|
57 |
|||
58 |
✓✓ | 5098 |
if (v->IsString()) { |
59 |
2944 |
Utf8Value s(env->isolate(), v); |
|
60 |
1472 |
return NodeBIO::NewFixed(*s, s.length()); |
|
61 |
} |
||
62 |
|||
63 |
✓✗ | 1077 |
if (v->IsArrayBufferView()) { |
64 |
1077 |
ArrayBufferViewContents<char> buf(v.As<ArrayBufferView>()); |
|
65 |
1077 |
return NodeBIO::NewFixed(buf.data(), buf.length()); |
|
66 |
} |
||
67 |
|||
68 |
return nullptr; |
||
69 |
} |
||
70 |
|||
71 |
namespace { |
||
72 |
944 |
int SSL_CTX_use_certificate_chain(SSL_CTX* ctx, |
|
73 |
X509Pointer&& x, |
||
74 |
STACK_OF(X509)* extra_certs, |
||
75 |
X509Pointer* cert, |
||
76 |
X509Pointer* issuer_) { |
||
77 |
✗✓ | 944 |
CHECK(!*issuer_); |
78 |
✗✓ | 944 |
CHECK(!*cert); |
79 |
944 |
X509* issuer = nullptr; |
|
80 |
|||
81 |
944 |
int ret = SSL_CTX_use_certificate(ctx, x.get()); |
|
82 |
|||
83 |
✓✗ | 944 |
if (ret) { |
84 |
// If we could set up our certificate, now proceed to |
||
85 |
// the CA certificates. |
||
86 |
944 |
SSL_CTX_clear_extra_chain_certs(ctx); |
|
87 |
|||
88 |
✓✓ | 1368 |
for (int i = 0; i < sk_X509_num(extra_certs); i++) { |
89 |
424 |
X509* ca = sk_X509_value(extra_certs, i); |
|
90 |
|||
91 |
// NOTE: Increments reference count on `ca` |
||
92 |
✗✓ | 424 |
if (!SSL_CTX_add1_chain_cert(ctx, ca)) { |
93 |
ret = 0; |
||
94 |
issuer = nullptr; |
||
95 |
break; |
||
96 |
} |
||
97 |
// Note that we must not free r if it was successfully |
||
98 |
// added to the chain (while we must free the main |
||
99 |
// certificate, since its reference count is increased |
||
100 |
// by SSL_CTX_use_certificate). |
||
101 |
|||
102 |
// Find issuer |
||
103 |
✓✓✗✓ ✓✓ |
424 |
if (issuer != nullptr || X509_check_issued(ca, x.get()) != X509_V_OK) |
104 |
4 |
continue; |
|
105 |
|||
106 |
420 |
issuer = ca; |
|
107 |
} |
||
108 |
} |
||
109 |
|||
110 |
// Try getting issuer from a cert store |
||
111 |
✓✗ | 944 |
if (ret) { |
112 |
✓✓ | 944 |
if (issuer == nullptr) { |
113 |
524 |
ret = SSL_CTX_get_issuer(ctx, x.get(), &issuer); |
|
114 |
524 |
ret = ret < 0 ? 0 : 1; |
|
115 |
// NOTE: get_cert_store doesn't increment reference count, |
||
116 |
// no need to free `store` |
||
117 |
} else { |
||
118 |
// Increment issuer reference count |
||
119 |
420 |
issuer = X509_dup(issuer); |
|
120 |
✗✓ | 420 |
if (issuer == nullptr) { |
121 |
ret = 0; |
||
122 |
} |
||
123 |
} |
||
124 |
} |
||
125 |
|||
126 |
944 |
issuer_->reset(issuer); |
|
127 |
|||
128 |
✓✗✓✗ ✓✗ |
944 |
if (ret && x != nullptr) { |
129 |
944 |
cert->reset(X509_dup(x.get())); |
|
130 |
✗✓ | 944 |
if (!*cert) |
131 |
ret = 0; |
||
132 |
} |
||
133 |
944 |
return ret; |
|
134 |
} |
||
135 |
|||
136 |
// Read a file that contains our certificate in "PEM" format, |
||
137 |
// possibly followed by a sequence of CA certificates that should be |
||
138 |
// sent to the peer in the Certificate message. |
||
139 |
// |
||
140 |
// Taken from OpenSSL - edited for style. |
||
141 |
932 |
int SSL_CTX_use_certificate_chain(SSL_CTX* ctx, |
|
142 |
BIOPointer&& in, |
||
143 |
X509Pointer* cert, |
||
144 |
X509Pointer* issuer) { |
||
145 |
// Just to ensure that `ERR_peek_last_error` below will return only errors |
||
146 |
// that we are interested in |
||
147 |
932 |
ERR_clear_error(); |
|
148 |
|||
149 |
X509Pointer x( |
||
150 |
1864 |
PEM_read_bio_X509_AUX(in.get(), nullptr, NoPasswordCallback, nullptr)); |
|
151 |
|||
152 |
✗✓ | 932 |
if (!x) |
153 |
return 0; |
||
154 |
|||
155 |
932 |
unsigned long err = 0; // NOLINT(runtime/int) |
|
156 |
|||
157 |
1864 |
StackOfX509 extra_certs(sk_X509_new_null()); |
|
158 |
✗✓ | 932 |
if (!extra_certs) |
159 |
return 0; |
||
160 |
|||
161 |
while (X509Pointer extra {PEM_read_bio_X509(in.get(), |
||
162 |
nullptr, |
||
163 |
NoPasswordCallback, |
||
164 |
✓✓ | 1347 |
nullptr)}) { |
165 |
✓✗ | 415 |
if (sk_X509_push(extra_certs.get(), extra.get())) { |
166 |
415 |
extra.release(); |
|
167 |
415 |
continue; |
|
168 |
} |
||
169 |
|||
170 |
return 0; |
||
171 |
415 |
} |
|
172 |
|||
173 |
// When the while loop ends, it's usually just EOF. |
||
174 |
932 |
err = ERR_peek_last_error(); |
|
175 |
✓✗✓✗ ✓✗ |
1864 |
if (ERR_GET_LIB(err) == ERR_LIB_PEM && |
176 |
932 |
ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { |
|
177 |
932 |
ERR_clear_error(); |
|
178 |
} else { |
||
179 |
// some real error |
||
180 |
return 0; |
||
181 |
} |
||
182 |
|||
183 |
1864 |
return SSL_CTX_use_certificate_chain(ctx, |
|
184 |
932 |
std::move(x), |
|
185 |
extra_certs.get(), |
||
186 |
cert, |
||
187 |
932 |
issuer); |
|
188 |
} |
||
189 |
|||
190 |
} // namespace |
||
191 |
|||
192 |
277 |
X509_STORE* NewRootCertStore() { |
|
193 |
✓✓✓✗ |
277 |
static std::vector<X509*> root_certs_vector; |
194 |
✓✓✓✗ |
277 |
static Mutex root_certs_vector_mutex; |
195 |
554 |
Mutex::ScopedLock lock(root_certs_vector_mutex); |
|
196 |
|||
197 |
✓✓✓✓ |
547 |
if (root_certs_vector.empty() && |
198 |
✓✓ | 270 |
per_process::cli_options->ssl_openssl_cert_store == false) { |
199 |
✓✓ | 35508 |
for (size_t i = 0; i < arraysize(root_certs); i++) { |
200 |
X509* x509 = |
||
201 |
35239 |
PEM_read_bio_X509(NodeBIO::NewFixed(root_certs[i], |
|
202 |
35239 |
strlen(root_certs[i])).get(), |
|
203 |
nullptr, // no re-use of X509 structure |
||
204 |
NoPasswordCallback, |
||
205 |
35239 |
nullptr); // no callback data |
|
206 |
|||
207 |
// Parse errors from the built-in roots are fatal. |
||
208 |
✗✓ | 35239 |
CHECK_NOT_NULL(x509); |
209 |
|||
210 |
35239 |
root_certs_vector.push_back(x509); |
|
211 |
} |
||
212 |
} |
||
213 |
|||
214 |
277 |
X509_STORE* store = X509_STORE_new(); |
|
215 |
✗✓ | 277 |
if (*system_cert_path != '\0') { |
216 |
ERR_set_mark(); |
||
217 |
X509_STORE_load_locations(store, system_cert_path, nullptr); |
||
218 |
ERR_pop_to_mark(); |
||
219 |
} |
||
220 |
|||
221 |
277 |
Mutex::ScopedLock cli_lock(node::per_process::cli_options_mutex); |
|
222 |
✓✓ | 277 |
if (per_process::cli_options->ssl_openssl_cert_store) { |
223 |
1 |
X509_STORE_set_default_paths(store); |
|
224 |
} else { |
||
225 |
✓✓ | 36432 |
for (X509* cert : root_certs_vector) { |
226 |
36156 |
X509_up_ref(cert); |
|
227 |
36156 |
X509_STORE_add_cert(store, cert); |
|
228 |
} |
||
229 |
} |
||
230 |
|||
231 |
277 |
return store; |
|
232 |
} |
||
233 |
|||
234 |
224 |
void GetRootCertificates(const FunctionCallbackInfo<Value>& args) { |
|
235 |
224 |
Environment* env = Environment::GetCurrent(args); |
|
236 |
✓✓ | 29568 |
Local<Value> result[arraysize(root_certs)]; |
237 |
|||
238 |
✓✓ | 29568 |
for (size_t i = 0; i < arraysize(root_certs); i++) { |
239 |
29344 |
if (!String::NewFromOneByte( |
|
240 |
env->isolate(), |
||
241 |
29344 |
reinterpret_cast<const uint8_t*>(root_certs[i])) |
|
242 |
✗✓ | 58688 |
.ToLocal(&result[i])) { |
243 |
return; |
||
244 |
} |
||
245 |
} |
||
246 |
|||
247 |
448 |
args.GetReturnValue().Set( |
|
248 |
Array::New(env->isolate(), result, arraysize(root_certs))); |
||
249 |
} |
||
250 |
|||
251 |
bool SecureContext::HasInstance(Environment* env, const Local<Value>& value) { |
||
252 |
return GetConstructorTemplate(env)->HasInstance(value); |
||
253 |
} |
||
254 |
|||
255 |
4389 |
Local<FunctionTemplate> SecureContext::GetConstructorTemplate( |
|
256 |
Environment* env) { |
||
257 |
4389 |
Local<FunctionTemplate> tmpl = env->secure_context_constructor_template(); |
|
258 |
✓✗ | 4389 |
if (tmpl.IsEmpty()) { |
259 |
4389 |
tmpl = env->NewFunctionTemplate(New); |
|
260 |
8778 |
tmpl->InstanceTemplate()->SetInternalFieldCount( |
|
261 |
SecureContext::kInternalFieldCount); |
||
262 |
4389 |
tmpl->Inherit(BaseObject::GetConstructorTemplate(env)); |
|
263 |
4389 |
tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "SecureContext")); |
|
264 |
|||
265 |
4389 |
env->SetProtoMethod(tmpl, "init", Init); |
|
266 |
4389 |
env->SetProtoMethod(tmpl, "setKey", SetKey); |
|
267 |
4389 |
env->SetProtoMethod(tmpl, "setCert", SetCert); |
|
268 |
4389 |
env->SetProtoMethod(tmpl, "addCACert", AddCACert); |
|
269 |
4389 |
env->SetProtoMethod(tmpl, "addCRL", AddCRL); |
|
270 |
4389 |
env->SetProtoMethod(tmpl, "addRootCerts", AddRootCerts); |
|
271 |
4389 |
env->SetProtoMethod(tmpl, "setCipherSuites", SetCipherSuites); |
|
272 |
4389 |
env->SetProtoMethod(tmpl, "setCiphers", SetCiphers); |
|
273 |
4389 |
env->SetProtoMethod(tmpl, "setSigalgs", SetSigalgs); |
|
274 |
4389 |
env->SetProtoMethod(tmpl, "setECDHCurve", SetECDHCurve); |
|
275 |
4389 |
env->SetProtoMethod(tmpl, "setDHParam", SetDHParam); |
|
276 |
4389 |
env->SetProtoMethod(tmpl, "setMaxProto", SetMaxProto); |
|
277 |
4389 |
env->SetProtoMethod(tmpl, "setMinProto", SetMinProto); |
|
278 |
4389 |
env->SetProtoMethod(tmpl, "getMaxProto", GetMaxProto); |
|
279 |
4389 |
env->SetProtoMethod(tmpl, "getMinProto", GetMinProto); |
|
280 |
4389 |
env->SetProtoMethod(tmpl, "setOptions", SetOptions); |
|
281 |
4389 |
env->SetProtoMethod(tmpl, "setSessionIdContext", SetSessionIdContext); |
|
282 |
4389 |
env->SetProtoMethod(tmpl, "setSessionTimeout", SetSessionTimeout); |
|
283 |
4389 |
env->SetProtoMethod(tmpl, "close", Close); |
|
284 |
4389 |
env->SetProtoMethod(tmpl, "loadPKCS12", LoadPKCS12); |
|
285 |
4389 |
env->SetProtoMethod(tmpl, "setTicketKeys", SetTicketKeys); |
|
286 |
4389 |
env->SetProtoMethod(tmpl, "setFreeListLength", SetFreeListLength); |
|
287 |
4389 |
env->SetProtoMethod(tmpl, "enableTicketKeyCallback", |
|
288 |
EnableTicketKeyCallback); |
||
289 |
|||
290 |
4389 |
env->SetProtoMethodNoSideEffect(tmpl, "getTicketKeys", GetTicketKeys); |
|
291 |
4389 |
env->SetProtoMethodNoSideEffect(tmpl, "getCertificate", |
|
292 |
GetCertificate<true>); |
||
293 |
4389 |
env->SetProtoMethodNoSideEffect(tmpl, "getIssuer", |
|
294 |
GetCertificate<false>); |
||
295 |
|||
296 |
#ifndef OPENSSL_NO_ENGINE |
||
297 |
4389 |
env->SetProtoMethod(tmpl, "setEngineKey", SetEngineKey); |
|
298 |
4389 |
env->SetProtoMethod(tmpl, "setClientCertEngine", SetClientCertEngine); |
|
299 |
#endif // !OPENSSL_NO_ENGINE |
||
300 |
|||
301 |
#define SET_INTEGER_CONSTANTS(name, value) \ |
||
302 |
tmpl->Set(FIXED_ONE_BYTE_STRING(env->isolate(), name), \ |
||
303 |
Integer::NewFromUnsigned(env->isolate(), value)); |
||
304 |
13167 |
SET_INTEGER_CONSTANTS("kTicketKeyReturnIndex", kTicketKeyReturnIndex); |
|
305 |
13167 |
SET_INTEGER_CONSTANTS("kTicketKeyHMACIndex", kTicketKeyHMACIndex); |
|
306 |
13167 |
SET_INTEGER_CONSTANTS("kTicketKeyAESIndex", kTicketKeyAESIndex); |
|
307 |
13167 |
SET_INTEGER_CONSTANTS("kTicketKeyNameIndex", kTicketKeyNameIndex); |
|
308 |
13167 |
SET_INTEGER_CONSTANTS("kTicketKeyIVIndex", kTicketKeyIVIndex); |
|
309 |
#undef SET_INTEGER_CONSTANTS |
||
310 |
|||
311 |
Local<FunctionTemplate> ctx_getter_templ = |
||
312 |
FunctionTemplate::New(env->isolate(), |
||
313 |
CtxGetter, |
||
314 |
Local<Value>(), |
||
315 |
4389 |
Signature::New(env->isolate(), tmpl)); |
|
316 |
|||
317 |
17556 |
tmpl->PrototypeTemplate()->SetAccessorProperty( |
|
318 |
FIXED_ONE_BYTE_STRING(env->isolate(), "_external"), |
||
319 |
ctx_getter_templ, |
||
320 |
Local<FunctionTemplate>(), |
||
321 |
static_cast<PropertyAttribute>(ReadOnly | DontDelete)); |
||
322 |
|||
323 |
4389 |
env->set_secure_context_constructor_template(tmpl); |
|
324 |
} |
||
325 |
4389 |
return tmpl; |
|
326 |
} |
||
327 |
|||
328 |
4389 |
void SecureContext::Initialize(Environment* env, Local<Object> target) { |
|
329 |
4389 |
env->SetConstructorFunction( |
|
330 |
target, |
||
331 |
"SecureContext", |
||
332 |
GetConstructorTemplate(env), |
||
333 |
Environment::SetConstructorFunctionFlag::NONE); |
||
334 |
|||
335 |
4389 |
env->SetMethodNoSideEffect(target, "getRootCertificates", |
|
336 |
GetRootCertificates); |
||
337 |
// Exposed for testing purposes only. |
||
338 |
4389 |
env->SetMethodNoSideEffect(target, "isExtraRootCertsFileLoaded", |
|
339 |
IsExtraRootCertsFileLoaded); |
||
340 |
4389 |
} |
|
341 |
|||
342 |
4949 |
void SecureContext::RegisterExternalReferences( |
|
343 |
ExternalReferenceRegistry* registry) { |
||
344 |
4949 |
registry->Register(New); |
|
345 |
4949 |
registry->Register(Init); |
|
346 |
4949 |
registry->Register(SetKey); |
|
347 |
4949 |
registry->Register(SetCert); |
|
348 |
4949 |
registry->Register(AddCACert); |
|
349 |
4949 |
registry->Register(AddCRL); |
|
350 |
4949 |
registry->Register(AddRootCerts); |
|
351 |
4949 |
registry->Register(SetCipherSuites); |
|
352 |
4949 |
registry->Register(SetCiphers); |
|
353 |
4949 |
registry->Register(SetSigalgs); |
|
354 |
4949 |
registry->Register(SetECDHCurve); |
|
355 |
4949 |
registry->Register(SetDHParam); |
|
356 |
4949 |
registry->Register(SetMaxProto); |
|
357 |
4949 |
registry->Register(SetMinProto); |
|
358 |
4949 |
registry->Register(GetMaxProto); |
|
359 |
4949 |
registry->Register(GetMinProto); |
|
360 |
4949 |
registry->Register(SetOptions); |
|
361 |
4949 |
registry->Register(SetSessionIdContext); |
|
362 |
4949 |
registry->Register(SetSessionTimeout); |
|
363 |
4949 |
registry->Register(Close); |
|
364 |
4949 |
registry->Register(LoadPKCS12); |
|
365 |
4949 |
registry->Register(SetTicketKeys); |
|
366 |
4949 |
registry->Register(SetFreeListLength); |
|
367 |
4949 |
registry->Register(EnableTicketKeyCallback); |
|
368 |
4949 |
registry->Register(GetTicketKeys); |
|
369 |
4949 |
registry->Register(GetCertificate<true>); |
|
370 |
4949 |
registry->Register(GetCertificate<false>); |
|
371 |
|||
372 |
#ifndef OPENSSL_NO_ENGINE |
||
373 |
4949 |
registry->Register(SetEngineKey); |
|
374 |
4949 |
registry->Register(SetClientCertEngine); |
|
375 |
#endif // !OPENSSL_NO_ENGINE |
||
376 |
|||
377 |
4949 |
registry->Register(CtxGetter); |
|
378 |
|||
379 |
4949 |
registry->Register(GetRootCertificates); |
|
380 |
4949 |
registry->Register(IsExtraRootCertsFileLoaded); |
|
381 |
4949 |
} |
|
382 |
|||
383 |
SecureContext* SecureContext::Create(Environment* env) { |
||
384 |
Local<Object> obj; |
||
385 |
if (!GetConstructorTemplate(env) |
||
386 |
->InstanceTemplate() |
||
387 |
->NewInstance(env->context()).ToLocal(&obj)) { |
||
388 |
return nullptr; |
||
389 |
} |
||
390 |
|||
391 |
return new SecureContext(env, obj); |
||
392 |
} |
||
393 |
|||
394 |
2480 |
SecureContext::SecureContext(Environment* env, Local<Object> wrap) |
|
395 |
2480 |
: BaseObject(env, wrap) { |
|
396 |
2480 |
MakeWeak(); |
|
397 |
2480 |
env->isolate()->AdjustAmountOfExternalAllocatedMemory(kExternalSize); |
|
398 |
2480 |
} |
|
399 |
|||
400 |
2471 |
inline void SecureContext::Reset() { |
|
401 |
✓✓ | 2471 |
if (ctx_ != nullptr) { |
402 |
2420 |
env()->isolate()->AdjustAmountOfExternalAllocatedMemory(-kExternalSize); |
|
403 |
} |
||
404 |
2471 |
ctx_.reset(); |
|
405 |
2471 |
cert_.reset(); |
|
406 |
2471 |
issuer_.reset(); |
|
407 |
2471 |
} |
|
408 |
|||
409 |
9884 |
SecureContext::~SecureContext() { |
|
410 |
4942 |
Reset(); |
|
411 |
9884 |
} |
|
412 |
|||
413 |
2480 |
void SecureContext::New(const FunctionCallbackInfo<Value>& args) { |
|
414 |
2480 |
Environment* env = Environment::GetCurrent(args); |
|
415 |
2480 |
new SecureContext(env, args.This()); |
|
416 |
2480 |
} |
|
417 |
|||
418 |
2478 |
void SecureContext::Init(const FunctionCallbackInfo<Value>& args) { |
|
419 |
SecureContext* sc; |
||
420 |
✗✓ | 2527 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
421 |
2478 |
Environment* env = sc->env(); |
|
422 |
|||
423 |
✗✓ | 2478 |
CHECK_EQ(args.Length(), 3); |
424 |
✗✓ | 2478 |
CHECK(args[1]->IsInt32()); |
425 |
✗✓ | 2478 |
CHECK(args[2]->IsInt32()); |
426 |
|||
427 |
✓✗ | 4956 |
int min_version = args[1].As<Int32>()->Value(); |
428 |
4956 |
int max_version = args[2].As<Int32>()->Value(); |
|
429 |
2478 |
const SSL_METHOD* method = TLS_method(); |
|
430 |
|||
431 |
✗✓ | 2478 |
if (max_version == 0) |
432 |
max_version = kMaxSupportedVersion; |
||
433 |
|||
434 |
✓✓ | 4956 |
if (args[0]->IsString()) { |
435 |
364 |
Utf8Value sslmethod(env->isolate(), args[0]); |
|
436 |
|||
437 |
// Note that SSLv2 and SSLv3 are disallowed but SSLv23_method and friends |
||
438 |
// are still accepted. They are OpenSSL's way of saying that all known |
||
439 |
// protocols below TLS 1.3 are supported unless explicitly disabled (which |
||
440 |
// we do below for SSLv2 and SSLv3.) |
||
441 |
✓✓ | 713 |
if (sslmethod == "SSLv2_method" || |
442 |
✓✓✓✓ ✓✓ |
713 |
sslmethod == "SSLv2_server_method" || |
443 |
348 |
sslmethod == "SSLv2_client_method") { |
|
444 |
17 |
THROW_ERR_TLS_INVALID_PROTOCOL_METHOD(env, "SSLv2 methods disabled"); |
|
445 |
17 |
return; |
|
446 |
✓✓ | 679 |
} else if (sslmethod == "SSLv3_method" || |
447 |
✓✓✓✓ ✓✓ |
679 |
sslmethod == "SSLv3_server_method" || |
448 |
331 |
sslmethod == "SSLv3_client_method") { |
|
449 |
17 |
THROW_ERR_TLS_INVALID_PROTOCOL_METHOD(env, "SSLv3 methods disabled"); |
|
450 |
17 |
return; |
|
451 |
✓✓ | 330 |
} else if (sslmethod == "SSLv23_method") { |
452 |
36 |
max_version = TLS1_2_VERSION; |
|
453 |
✓✓ | 294 |
} else if (sslmethod == "SSLv23_server_method") { |
454 |
1 |
max_version = TLS1_2_VERSION; |
|
455 |
1 |
method = TLS_server_method(); |
|
456 |
✓✓ | 293 |
} else if (sslmethod == "SSLv23_client_method") { |
457 |
1 |
max_version = TLS1_2_VERSION; |
|
458 |
1 |
method = TLS_client_method(); |
|
459 |
✓✓ | 292 |
} else if (sslmethod == "TLS_method") { |
460 |
53 |
min_version = 0; |
|
461 |
53 |
max_version = kMaxSupportedVersion; |
|
462 |
✗✓ | 239 |
} else if (sslmethod == "TLS_server_method") { |
463 |
min_version = 0; |
||
464 |
max_version = kMaxSupportedVersion; |
||
465 |
method = TLS_server_method(); |
||
466 |
✗✓ | 239 |
} else if (sslmethod == "TLS_client_method") { |
467 |
min_version = 0; |
||
468 |
max_version = kMaxSupportedVersion; |
||
469 |
method = TLS_client_method(); |
||
470 |
✓✓ | 239 |
} else if (sslmethod == "TLSv1_method") { |
471 |
71 |
min_version = TLS1_VERSION; |
|
472 |
71 |
max_version = TLS1_VERSION; |
|
473 |
✓✓ | 168 |
} else if (sslmethod == "TLSv1_server_method") { |
474 |
1 |
min_version = TLS1_VERSION; |
|
475 |
1 |
max_version = TLS1_VERSION; |
|
476 |
1 |
method = TLS_server_method(); |
|
477 |
✓✓ | 167 |
} else if (sslmethod == "TLSv1_client_method") { |
478 |
1 |
min_version = TLS1_VERSION; |
|
479 |
1 |
max_version = TLS1_VERSION; |
|
480 |
1 |
method = TLS_client_method(); |
|
481 |
✓✓ | 166 |
} else if (sslmethod == "TLSv1_1_method") { |
482 |
71 |
min_version = TLS1_1_VERSION; |
|
483 |
71 |
max_version = TLS1_1_VERSION; |
|
484 |
✓✓ | 95 |
} else if (sslmethod == "TLSv1_1_server_method") { |
485 |
1 |
min_version = TLS1_1_VERSION; |
|
486 |
1 |
max_version = TLS1_1_VERSION; |
|
487 |
1 |
method = TLS_server_method(); |
|
488 |
✓✓ | 94 |
} else if (sslmethod == "TLSv1_1_client_method") { |
489 |
1 |
min_version = TLS1_1_VERSION; |
|
490 |
1 |
max_version = TLS1_1_VERSION; |
|
491 |
1 |
method = TLS_client_method(); |
|
492 |
✓✓ | 93 |
} else if (sslmethod == "TLSv1_2_method") { |
493 |
75 |
min_version = TLS1_2_VERSION; |
|
494 |
75 |
max_version = TLS1_2_VERSION; |
|
495 |
✓✓ | 18 |
} else if (sslmethod == "TLSv1_2_server_method") { |
496 |
2 |
min_version = TLS1_2_VERSION; |
|
497 |
2 |
max_version = TLS1_2_VERSION; |
|
498 |
2 |
method = TLS_server_method(); |
|
499 |
✓✓ | 16 |
} else if (sslmethod == "TLSv1_2_client_method") { |
500 |
1 |
min_version = TLS1_2_VERSION; |
|
501 |
1 |
max_version = TLS1_2_VERSION; |
|
502 |
1 |
method = TLS_client_method(); |
|
503 |
} else { |
||
504 |
15 |
const std::string msg("Unknown method: "); |
|
505 |
15 |
THROW_ERR_TLS_INVALID_PROTOCOL_METHOD(env, (msg + * sslmethod).c_str()); |
|
506 |
15 |
return; |
|
507 |
} |
||
508 |
} |
||
509 |
|||
510 |
2429 |
sc->ctx_.reset(SSL_CTX_new(method)); |
|
511 |
2429 |
SSL_CTX_set_app_data(sc->ctx_.get(), sc); |
|
512 |
|||
513 |
// Disable SSLv2 in the case when method == TLS_method() and the |
||
514 |
// cipher list contains SSLv2 ciphers (not the default, should be rare.) |
||
515 |
// The bundled OpenSSL doesn't have SSLv2 support but the system OpenSSL may. |
||
516 |
// SSLv3 is disabled because it's susceptible to downgrade attacks (POODLE.) |
||
517 |
2429 |
SSL_CTX_set_options(sc->ctx_.get(), SSL_OP_NO_SSLv2); |
|
518 |
2429 |
SSL_CTX_set_options(sc->ctx_.get(), SSL_OP_NO_SSLv3); |
|
519 |
#if OPENSSL_VERSION_MAJOR >= 3 |
||
520 |
2429 |
SSL_CTX_set_options(sc->ctx_.get(), SSL_OP_ALLOW_CLIENT_RENEGOTIATION); |
|
521 |
#endif |
||
522 |
|||
523 |
// Enable automatic cert chaining. This is enabled by default in OpenSSL, but |
||
524 |
// disabled by default in BoringSSL. Enable it explicitly to make the |
||
525 |
// behavior match when Node is built with BoringSSL. |
||
526 |
2429 |
SSL_CTX_clear_mode(sc->ctx_.get(), SSL_MODE_NO_AUTO_CHAIN); |
|
527 |
|||
528 |
// SSL session cache configuration |
||
529 |
2429 |
SSL_CTX_set_session_cache_mode(sc->ctx_.get(), |
|
530 |
SSL_SESS_CACHE_CLIENT | |
||
531 |
SSL_SESS_CACHE_SERVER | |
||
532 |
SSL_SESS_CACHE_NO_INTERNAL | |
||
533 |
SSL_SESS_CACHE_NO_AUTO_CLEAR); |
||
534 |
|||
535 |
2429 |
SSL_CTX_set_min_proto_version(sc->ctx_.get(), min_version); |
|
536 |
2429 |
SSL_CTX_set_max_proto_version(sc->ctx_.get(), max_version); |
|
537 |
|||
538 |
// OpenSSL 1.1.0 changed the ticket key size, but the OpenSSL 1.0.x size was |
||
539 |
// exposed in the public API. To retain compatibility, install a callback |
||
540 |
// which restores the old algorithm. |
||
541 |
✓✗ | 4858 |
if (RAND_bytes(sc->ticket_key_name_, sizeof(sc->ticket_key_name_)) <= 0 || |
542 |
✓✗✗✓ ✗✓ |
4858 |
RAND_bytes(sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_)) <= 0 || |
543 |
2429 |
RAND_bytes(sc->ticket_key_aes_, sizeof(sc->ticket_key_aes_)) <= 0) { |
|
544 |
return THROW_ERR_CRYPTO_OPERATION_FAILED( |
||
545 |
env, "Error generating ticket keys"); |
||
546 |
} |
||
547 |
2429 |
SSL_CTX_set_tlsext_ticket_key_cb(sc->ctx_.get(), TicketCompatibilityCallback); |
|
548 |
} |
||
549 |
|||
550 |
12372 |
SSLPointer SecureContext::CreateSSL() { |
|
551 |
12372 |
return SSLPointer(SSL_new(ctx_.get())); |
|
552 |
} |
||
553 |
|||
554 |
12372 |
void SecureContext::SetNewSessionCallback(NewSessionCb cb) { |
|
555 |
12372 |
SSL_CTX_sess_set_new_cb(ctx_.get(), cb); |
|
556 |
12372 |
} |
|
557 |
|||
558 |
12372 |
void SecureContext::SetGetSessionCallback(GetSessionCb cb) { |
|
559 |
12372 |
SSL_CTX_sess_set_get_cb(ctx_.get(), cb); |
|
560 |
12372 |
} |
|
561 |
|||
562 |
937 |
void SecureContext::SetSelectSNIContextCallback(SelectSNIContextCb cb) { |
|
563 |
937 |
SSL_CTX_set_tlsext_servername_callback(ctx_.get(), cb); |
|
564 |
937 |
} |
|
565 |
|||
566 |
8 |
void SecureContext::SetKeylogCallback(KeylogCb cb) { |
|
567 |
8 |
SSL_CTX_set_keylog_callback(ctx_.get(), cb); |
|
568 |
8 |
} |
|
569 |
|||
570 |
914 |
void SecureContext::SetKey(const FunctionCallbackInfo<Value>& args) { |
|
571 |
914 |
Environment* env = Environment::GetCurrent(args); |
|
572 |
|||
573 |
SecureContext* sc; |
||
574 |
✗✓ | 922 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
575 |
|||
576 |
✗✓ | 914 |
CHECK_GE(args.Length(), 1); // Private key argument is mandatory |
577 |
|||
578 |
914 |
BIOPointer bio(LoadBIO(env, args[0])); |
|
579 |
✗✓ | 914 |
if (!bio) |
580 |
return; |
||
581 |
|||
582 |
✓✗ | 914 |
ByteSource passphrase; |
583 |
✓✓ | 1828 |
if (args[1]->IsString()) |
584 |
48 |
passphrase = ByteSource::FromString(env, args[1].As<String>()); |
|
585 |
// This redirection is necessary because the PasswordCallback expects a |
||
586 |
// pointer to a pointer to the passphrase ByteSource to allow passing in |
||
587 |
// const ByteSources. |
||
588 |
914 |
const ByteSource* pass_ptr = &passphrase; |
|
589 |
|||
590 |
EVPKeyPointer key( |
||
591 |
PEM_read_bio_PrivateKey(bio.get(), |
||
592 |
nullptr, |
||
593 |
PasswordCallback, |
||
594 |
914 |
&pass_ptr)); |
|
595 |
|||
596 |
✓✓ | 914 |
if (!key) |
597 |
7 |
return ThrowCryptoError(env, ERR_get_error(), "PEM_read_bio_PrivateKey"); |
|
598 |
|||
599 |
✓✓ | 907 |
if (!SSL_CTX_use_PrivateKey(sc->ctx_.get(), key.get())) |
600 |
1 |
return ThrowCryptoError(env, ERR_get_error(), "SSL_CTX_use_PrivateKey"); |
|
601 |
} |
||
602 |
|||
603 |
8 |
void SecureContext::SetSigalgs(const FunctionCallbackInfo<Value>& args) { |
|
604 |
SecureContext* sc; |
||
605 |
✗✓ | 8 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
606 |
8 |
Environment* env = sc->env(); |
|
607 |
ClearErrorOnReturn clear_error_on_return; |
||
608 |
|||
609 |
✗✓ | 8 |
CHECK_EQ(args.Length(), 1); |
610 |
✗✓ | 16 |
CHECK(args[0]->IsString()); |
611 |
|||
612 |
8 |
const Utf8Value sigalgs(env->isolate(), args[0]); |
|
613 |
|||
614 |
✗✓ | 8 |
if (!SSL_CTX_set1_sigalgs_list(sc->ctx_.get(), *sigalgs)) |
615 |
return ThrowCryptoError(env, ERR_get_error()); |
||
616 |
} |
||
617 |
|||
618 |
#ifndef OPENSSL_NO_ENGINE |
||
619 |
void SecureContext::SetEngineKey(const FunctionCallbackInfo<Value>& args) { |
||
620 |
Environment* env = Environment::GetCurrent(args); |
||
621 |
|||
622 |
SecureContext* sc; |
||
623 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
||
624 |
|||
625 |
CHECK_EQ(args.Length(), 2); |
||
626 |
|||
627 |
CryptoErrorStore errors; |
||
628 |
Utf8Value engine_id(env->isolate(), args[1]); |
||
629 |
EnginePointer engine = LoadEngineById(*engine_id, &errors); |
||
630 |
if (!engine) { |
||
631 |
Local<Value> exception; |
||
632 |
if (errors.ToException(env).ToLocal(&exception)) |
||
633 |
env->isolate()->ThrowException(exception); |
||
634 |
return; |
||
635 |
} |
||
636 |
|||
637 |
if (!ENGINE_init(engine.get())) { |
||
638 |
return THROW_ERR_CRYPTO_OPERATION_FAILED( |
||
639 |
env, "Failure to initialize engine"); |
||
640 |
} |
||
641 |
|||
642 |
engine.finish_on_exit = true; |
||
643 |
|||
644 |
Utf8Value key_name(env->isolate(), args[0]); |
||
645 |
EVPKeyPointer key(ENGINE_load_private_key(engine.get(), *key_name, |
||
646 |
nullptr, nullptr)); |
||
647 |
|||
648 |
if (!key) |
||
649 |
return ThrowCryptoError(env, ERR_get_error(), "ENGINE_load_private_key"); |
||
650 |
|||
651 |
if (!SSL_CTX_use_PrivateKey(sc->ctx_.get(), key.get())) |
||
652 |
return ThrowCryptoError(env, ERR_get_error(), "SSL_CTX_use_PrivateKey"); |
||
653 |
|||
654 |
sc->private_key_engine_ = std::move(engine); |
||
655 |
} |
||
656 |
#endif // !OPENSSL_NO_ENGINE |
||
657 |
|||
658 |
932 |
void SecureContext::SetCert(const FunctionCallbackInfo<Value>& args) { |
|
659 |
932 |
Environment* env = Environment::GetCurrent(args); |
|
660 |
|||
661 |
SecureContext* sc; |
||
662 |
✗✓ | 932 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
663 |
|||
664 |
✗✓ | 932 |
CHECK_GE(args.Length(), 1); // Certificate argument is mandator |
665 |
|||
666 |
932 |
BIOPointer bio(LoadBIO(env, args[0])); |
|
667 |
✗✓ | 932 |
if (!bio) |
668 |
return; |
||
669 |
|||
670 |
932 |
sc->cert_.reset(); |
|
671 |
932 |
sc->issuer_.reset(); |
|
672 |
|||
673 |
✗✓ | 932 |
if (!SSL_CTX_use_certificate_chain( |
674 |
932 |
sc->ctx_.get(), |
|
675 |
932 |
std::move(bio), |
|
676 |
932 |
&sc->cert_, |
|
677 |
932 |
&sc->issuer_)) { |
|
678 |
return ThrowCryptoError( |
||
679 |
env, |
||
680 |
ERR_get_error(), |
||
681 |
"SSL_CTX_use_certificate_chain"); |
||
682 |
} |
||
683 |
} |
||
684 |
|||
685 |
623 |
void SecureContext::AddCACert(const FunctionCallbackInfo<Value>& args) { |
|
686 |
623 |
Environment* env = Environment::GetCurrent(args); |
|
687 |
|||
688 |
SecureContext* sc; |
||
689 |
✗✓ | 623 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
690 |
ClearErrorOnReturn clear_error_on_return; |
||
691 |
|||
692 |
✗✓ | 623 |
CHECK_GE(args.Length(), 1); // CA certificate argument is mandatory |
693 |
|||
694 |
623 |
BIOPointer bio(LoadBIO(env, args[0])); |
|
695 |
✗✓ | 623 |
if (!bio) |
696 |
return; |
||
697 |
|||
698 |
623 |
X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_.get()); |
|
699 |
1588 |
while (X509* x509 = PEM_read_bio_X509_AUX( |
|
700 |
✓✓ | 1588 |
bio.get(), nullptr, NoPasswordCallback, nullptr)) { |
701 |
✓✓ | 965 |
if (cert_store == root_cert_store) { |
702 |
1 |
cert_store = NewRootCertStore(); |
|
703 |
1 |
SSL_CTX_set_cert_store(sc->ctx_.get(), cert_store); |
|
704 |
} |
||
705 |
965 |
X509_STORE_add_cert(cert_store, x509); |
|
706 |
965 |
SSL_CTX_add_client_CA(sc->ctx_.get(), x509); |
|
707 |
965 |
X509_free(x509); |
|
708 |
965 |
} |
|
709 |
} |
||
710 |
|||
711 |
2 |
void SecureContext::AddCRL(const FunctionCallbackInfo<Value>& args) { |
|
712 |
2 |
Environment* env = Environment::GetCurrent(args); |
|
713 |
|||
714 |
SecureContext* sc; |
||
715 |
✗✓ | 3 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
716 |
|||
717 |
✗✓ | 2 |
CHECK_GE(args.Length(), 1); // CRL argument is mandatory |
718 |
|||
719 |
ClearErrorOnReturn clear_error_on_return; |
||
720 |
|||
721 |
2 |
BIOPointer bio(LoadBIO(env, args[0])); |
|
722 |
✗✓ | 2 |
if (!bio) |
723 |
return; |
||
724 |
|||
725 |
DeleteFnPtr<X509_CRL, X509_CRL_free> crl( |
||
726 |
2 |
PEM_read_bio_X509_CRL(bio.get(), nullptr, NoPasswordCallback, nullptr)); |
|
727 |
|||
728 |
✓✓ | 2 |
if (!crl) |
729 |
1 |
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to parse CRL"); |
|
730 |
|||
731 |
1 |
X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_.get()); |
|
732 |
✗✓ | 1 |
if (cert_store == root_cert_store) { |
733 |
cert_store = NewRootCertStore(); |
||
734 |
SSL_CTX_set_cert_store(sc->ctx_.get(), cert_store); |
||
735 |
} |
||
736 |
|||
737 |
1 |
X509_STORE_add_crl(cert_store, crl.get()); |
|
738 |
1 |
X509_STORE_set_flags(cert_store, |
|
739 |
X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); |
||
740 |
} |
||
741 |
|||
742 |
1826 |
void SecureContext::AddRootCerts(const FunctionCallbackInfo<Value>& args) { |
|
743 |
SecureContext* sc; |
||
744 |
✗✓ | 1826 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
745 |
1826 |
ClearErrorOnReturn clear_error_on_return; |
|
746 |
|||
747 |
✓✓ | 1826 |
if (root_cert_store == nullptr) { |
748 |
265 |
root_cert_store = NewRootCertStore(); |
|
749 |
} |
||
750 |
|||
751 |
// Increment reference count so global store is not deleted along with CTX. |
||
752 |
1826 |
X509_STORE_up_ref(root_cert_store); |
|
753 |
1826 |
SSL_CTX_set_cert_store(sc->ctx_.get(), root_cert_store); |
|
754 |
} |
||
755 |
|||
756 |
2353 |
void SecureContext::SetCipherSuites(const FunctionCallbackInfo<Value>& args) { |
|
757 |
// BoringSSL doesn't allow API config of TLS1.3 cipher suites. |
||
758 |
#ifndef OPENSSL_IS_BORINGSSL |
||
759 |
SecureContext* sc; |
||
760 |
✗✓ | 2354 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
761 |
2353 |
Environment* env = sc->env(); |
|
762 |
ClearErrorOnReturn clear_error_on_return; |
||
763 |
|||
764 |
✗✓ | 2353 |
CHECK_EQ(args.Length(), 1); |
765 |
✗✓ | 4706 |
CHECK(args[0]->IsString()); |
766 |
|||
767 |
2353 |
const Utf8Value ciphers(env->isolate(), args[0]); |
|
768 |
✓✓ | 2353 |
if (!SSL_CTX_set_ciphersuites(sc->ctx_.get(), *ciphers)) |
769 |
1 |
return ThrowCryptoError(env, ERR_get_error(), "Failed to set ciphers"); |
|
770 |
#endif |
||
771 |
} |
||
772 |
|||
773 |
2355 |
void SecureContext::SetCiphers(const FunctionCallbackInfo<Value>& args) { |
|
774 |
SecureContext* sc; |
||
775 |
✗✓ | 2370 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
776 |
2355 |
Environment* env = sc->env(); |
|
777 |
ClearErrorOnReturn clear_error_on_return; |
||
778 |
|||
779 |
✗✓ | 2355 |
CHECK_EQ(args.Length(), 1); |
780 |
✗✓ | 4710 |
CHECK(args[0]->IsString()); |
781 |
|||
782 |
2355 |
Utf8Value ciphers(env->isolate(), args[0]); |
|
783 |
✓✓ | 2355 |
if (!SSL_CTX_set_cipher_list(sc->ctx_.get(), *ciphers)) { |
784 |
15 |
unsigned long err = ERR_get_error(); // NOLINT(runtime/int) |
|
785 |
|||
786 |
✓✓✓✗ ✓✓ |
15 |
if (strlen(*ciphers) == 0 && ERR_GET_REASON(err) == SSL_R_NO_CIPHER_MATCH) { |
787 |
// TLS1.2 ciphers were deliberately cleared, so don't consider |
||
788 |
// SSL_R_NO_CIPHER_MATCH to be an error (this is how _set_cipher_suites() |
||
789 |
// works). If the user actually sets a value (like "no-such-cipher"), then |
||
790 |
// that's actually an error. |
||
791 |
11 |
return; |
|
792 |
} |
||
793 |
4 |
return ThrowCryptoError(env, err, "Failed to set ciphers"); |
|
794 |
} |
||
795 |
} |
||
796 |
|||
797 |
2347 |
void SecureContext::SetECDHCurve(const FunctionCallbackInfo<Value>& args) { |
|
798 |
SecureContext* sc; |
||
799 |
✗✓ | 2350 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
800 |
2347 |
Environment* env = sc->env(); |
|
801 |
|||
802 |
✗✓ | 2347 |
CHECK_GE(args.Length(), 1); // ECDH curve name argument is mandatory |
803 |
✗✓ | 4694 |
CHECK(args[0]->IsString()); |
804 |
|||
805 |
2347 |
Utf8Value curve(env->isolate(), args[0]); |
|
806 |
|||
807 |
✓✓✓✓ ✓✓ |
2357 |
if (strcmp(*curve, "auto") != 0 && |
808 |
10 |
!SSL_CTX_set1_curves_list(sc->ctx_.get(), *curve)) { |
|
809 |
3 |
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to set ECDH curve"); |
|
810 |
} |
||
811 |
} |
||
812 |
|||
813 |
10 |
void SecureContext::SetDHParam(const FunctionCallbackInfo<Value>& args) { |
|
814 |
SecureContext* sc; |
||
815 |
✗✓ | 13 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.This()); |
816 |
10 |
Environment* env = sc->env(); |
|
817 |
ClearErrorOnReturn clear_error_on_return; |
||
818 |
|||
819 |
✗✓ | 10 |
CHECK_GE(args.Length(), 1); // DH argument is mandatory |
820 |
|||
821 |
✓✗ | 10 |
DHPointer dh; |
822 |
{ |
||
823 |
10 |
BIOPointer bio(LoadBIO(env, args[0])); |
|
824 |
✗✓ | 10 |
if (!bio) |
825 |
return; |
||
826 |
|||
827 |
10 |
dh.reset(PEM_read_bio_DHparams(bio.get(), nullptr, nullptr, nullptr)); |
|
828 |
} |
||
829 |
|||
830 |
// Invalid dhparam is silently discarded and DHE is no longer used. |
||
831 |
✓✓ | 10 |
if (!dh) |
832 |
1 |
return; |
|
833 |
|||
834 |
const BIGNUM* p; |
||
835 |
9 |
DH_get0_pqg(dh.get(), &p, nullptr, nullptr); |
|
836 |
9 |
const int size = BN_num_bits(p); |
|
837 |
✓✓ | 9 |
if (size < 1024) { |
838 |
2 |
return THROW_ERR_INVALID_ARG_VALUE( |
|
839 |
2 |
env, "DH parameter is less than 1024 bits"); |
|
840 |
✓✓ | 7 |
} else if (size < 2048) { |
841 |
6 |
args.GetReturnValue().Set(FIXED_ONE_BYTE_STRING( |
|
842 |
env->isolate(), "DH parameter is less than 2048 bits")); |
||
843 |
} |
||
844 |
|||
845 |
7 |
SSL_CTX_set_options(sc->ctx_.get(), SSL_OP_SINGLE_DH_USE); |
|
846 |
|||
847 |
✗✓ | 7 |
if (!SSL_CTX_set_tmp_dh(sc->ctx_.get(), dh.get())) { |
848 |
return THROW_ERR_CRYPTO_OPERATION_FAILED( |
||
849 |
env, "Error setting temp DH parameter"); |
||
850 |
} |
||
851 |
} |
||
852 |
|||
853 |
11 |
void SecureContext::SetMinProto(const FunctionCallbackInfo<Value>& args) { |
|
854 |
SecureContext* sc; |
||
855 |
✗✓ | 11 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
856 |
|||
857 |
✗✓ | 11 |
CHECK_EQ(args.Length(), 1); |
858 |
✗✓ | 11 |
CHECK(args[0]->IsInt32()); |
859 |
|||
860 |
22 |
int version = args[0].As<Int32>()->Value(); |
|
861 |
|||
862 |
✗✓ | 11 |
CHECK(SSL_CTX_set_min_proto_version(sc->ctx_.get(), version)); |
863 |
} |
||
864 |
|||
865 |
146 |
void SecureContext::SetMaxProto(const FunctionCallbackInfo<Value>& args) { |
|
866 |
SecureContext* sc; |
||
867 |
✗✓ | 146 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
868 |
|||
869 |
✗✓ | 146 |
CHECK_EQ(args.Length(), 1); |
870 |
✗✓ | 146 |
CHECK(args[0]->IsInt32()); |
871 |
|||
872 |
292 |
int version = args[0].As<Int32>()->Value(); |
|
873 |
|||
874 |
✗✓ | 146 |
CHECK(SSL_CTX_set_max_proto_version(sc->ctx_.get(), version)); |
875 |
} |
||
876 |
|||
877 |
157 |
void SecureContext::GetMinProto(const FunctionCallbackInfo<Value>& args) { |
|
878 |
SecureContext* sc; |
||
879 |
✗✓ | 157 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
880 |
|||
881 |
✗✓ | 157 |
CHECK_EQ(args.Length(), 0); |
882 |
|||
883 |
long version = // NOLINT(runtime/int) |
||
884 |
157 |
SSL_CTX_get_min_proto_version(sc->ctx_.get()); |
|
885 |
✓✗ | 314 |
args.GetReturnValue().Set(static_cast<uint32_t>(version)); |
886 |
} |
||
887 |
|||
888 |
467 |
void SecureContext::GetMaxProto(const FunctionCallbackInfo<Value>& args) { |
|
889 |
SecureContext* sc; |
||
890 |
✗✓ | 467 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
891 |
|||
892 |
✗✓ | 467 |
CHECK_EQ(args.Length(), 0); |
893 |
|||
894 |
long version = // NOLINT(runtime/int) |
||
895 |
467 |
SSL_CTX_get_max_proto_version(sc->ctx_.get()); |
|
896 |
✓✗ | 934 |
args.GetReturnValue().Set(static_cast<uint32_t>(version)); |
897 |
} |
||
898 |
|||
899 |
915 |
void SecureContext::SetOptions(const FunctionCallbackInfo<Value>& args) { |
|
900 |
915 |
Environment* env = Environment::GetCurrent(args); |
|
901 |
SecureContext* sc; |
||
902 |
✗✓ | 915 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
903 |
|||
904 |
✗✓ | 915 |
CHECK_GE(args.Length(), 1); |
905 |
✗✓ | 915 |
CHECK(args[0]->IsNumber()); |
906 |
|||
907 |
✓✗ | 915 |
int64_t val = args[0]->IntegerValue(env->context()).FromMaybe(0); |
908 |
|||
909 |
915 |
SSL_CTX_set_options(sc->ctx_.get(), |
|
910 |
static_cast<long>(val)); // NOLINT(runtime/int) |
||
911 |
} |
||
912 |
|||
913 |
844 |
void SecureContext::SetSessionIdContext( |
|
914 |
const FunctionCallbackInfo<Value>& args) { |
||
915 |
SecureContext* sc; |
||
916 |
✗✓ | 1688 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
917 |
844 |
Environment* env = sc->env(); |
|
918 |
|||
919 |
✗✓ | 844 |
CHECK_GE(args.Length(), 1); |
920 |
✗✓ | 1688 |
CHECK(args[0]->IsString()); |
921 |
|||
922 |
844 |
const Utf8Value sessionIdContext(env->isolate(), args[0]); |
|
923 |
const unsigned char* sid_ctx = |
||
924 |
844 |
reinterpret_cast<const unsigned char*>(*sessionIdContext); |
|
925 |
844 |
unsigned int sid_ctx_len = sessionIdContext.length(); |
|
926 |
|||
927 |
✓✗ | 844 |
if (SSL_CTX_set_session_id_context(sc->ctx_.get(), sid_ctx, sid_ctx_len) == 1) |
928 |
844 |
return; |
|
929 |
|||
930 |
BUF_MEM* mem; |
||
931 |
Local<String> message; |
||
932 |
|||
933 |
BIOPointer bio(BIO_new(BIO_s_mem())); |
||
934 |
if (!bio) { |
||
935 |
message = FIXED_ONE_BYTE_STRING(env->isolate(), |
||
936 |
"SSL_CTX_set_session_id_context error"); |
||
937 |
} else { |
||
938 |
ERR_print_errors(bio.get()); |
||
939 |
BIO_get_mem_ptr(bio.get(), &mem); |
||
940 |
message = OneByteString(env->isolate(), mem->data, mem->length); |
||
941 |
} |
||
942 |
|||
943 |
env->isolate()->ThrowException(Exception::TypeError(message)); |
||
944 |
} |
||
945 |
|||
946 |
1 |
void SecureContext::SetSessionTimeout(const FunctionCallbackInfo<Value>& args) { |
|
947 |
SecureContext* sc; |
||
948 |
✗✓ | 1 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
949 |
|||
950 |
✗✓ | 1 |
CHECK_GE(args.Length(), 1); |
951 |
✗✓ | 1 |
CHECK(args[0]->IsInt32()); |
952 |
|||
953 |
2 |
int32_t sessionTimeout = args[0].As<Int32>()->Value(); |
|
954 |
1 |
SSL_CTX_set_timeout(sc->ctx_.get(), sessionTimeout); |
|
955 |
} |
||
956 |
|||
957 |
void SecureContext::Close(const FunctionCallbackInfo<Value>& args) { |
||
958 |
SecureContext* sc; |
||
959 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
||
960 |
sc->Reset(); |
||
961 |
} |
||
962 |
|||
963 |
// Takes .pfx or .p12 and password in string or buffer format |
||
964 |
18 |
void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) { |
|
965 |
18 |
Environment* env = Environment::GetCurrent(args); |
|
966 |
|||
967 |
18 |
std::vector<char> pass; |
|
968 |
18 |
bool ret = false; |
|
969 |
|||
970 |
SecureContext* sc; |
||
971 |
✗✓ | 18 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
972 |
ClearErrorOnReturn clear_error_on_return; |
||
973 |
|||
974 |
✗✓ | 18 |
if (args.Length() < 1) { |
975 |
return THROW_ERR_MISSING_ARGS(env, "PFX certificate argument is mandatory"); |
||
976 |
} |
||
977 |
|||
978 |
18 |
BIOPointer in(LoadBIO(env, args[0])); |
|
979 |
✗✓ | 18 |
if (!in) { |
980 |
return THROW_ERR_CRYPTO_OPERATION_FAILED( |
||
981 |
env, "Unable to load PFX certificate"); |
||
982 |
} |
||
983 |
|||
984 |
✓✓ | 18 |
if (args.Length() >= 2) { |
985 |
✗✓ | 15 |
THROW_AND_RETURN_IF_NOT_BUFFER(env, args[1], "Pass phrase"); |
986 |
30 |
Local<ArrayBufferView> abv = args[1].As<ArrayBufferView>(); |
|
987 |
15 |
size_t passlen = abv->ByteLength(); |
|
988 |
15 |
pass.resize(passlen + 1); |
|
989 |
15 |
abv->CopyContents(pass.data(), passlen); |
|
990 |
15 |
pass[passlen] = '\0'; |
|
991 |
} |
||
992 |
|||
993 |
// Free previous certs |
||
994 |
18 |
sc->issuer_.reset(); |
|
995 |
18 |
sc->cert_.reset(); |
|
996 |
|||
997 |
18 |
X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_.get()); |
|
998 |
|||
999 |
18 |
DeleteFnPtr<PKCS12, PKCS12_free> p12; |
|
1000 |
18 |
EVPKeyPointer pkey; |
|
1001 |
18 |
X509Pointer cert; |
|
1002 |
18 |
StackOfX509 extra_certs; |
|
1003 |
|||
1004 |
18 |
PKCS12* p12_ptr = nullptr; |
|
1005 |
18 |
EVP_PKEY* pkey_ptr = nullptr; |
|
1006 |
18 |
X509* cert_ptr = nullptr; |
|
1007 |
18 |
STACK_OF(X509)* extra_certs_ptr = nullptr; |
|
1008 |
18 |
if (d2i_PKCS12_bio(in.get(), &p12_ptr) && |
|
1009 |
✓✓ | 32 |
(p12.reset(p12_ptr), true) && // Move ownership to the smart pointer. |
1010 |
16 |
PKCS12_parse(p12.get(), pass.data(), |
|
1011 |
&pkey_ptr, |
||
1012 |
&cert_ptr, |
||
1013 |
&extra_certs_ptr) && |
||
1014 |
12 |
(pkey.reset(pkey_ptr), cert.reset(cert_ptr), |
|
1015 |
✓✗ | 24 |
extra_certs.reset(extra_certs_ptr), true) && // Move ownership. |
1016 |
12 |
SSL_CTX_use_certificate_chain(sc->ctx_.get(), |
|
1017 |
12 |
std::move(cert), |
|
1018 |
extra_certs.get(), |
||
1019 |
12 |
&sc->cert_, |
|
1020 |
✓✓✓✗ ✓✓ |
46 |
&sc->issuer_) && |
1021 |
12 |
SSL_CTX_use_PrivateKey(sc->ctx_.get(), pkey.get())) { |
|
1022 |
// Add CA certs too |
||
1023 |
✓✓ | 21 |
for (int i = 0; i < sk_X509_num(extra_certs.get()); i++) { |
1024 |
9 |
X509* ca = sk_X509_value(extra_certs.get(), i); |
|
1025 |
|||
1026 |
✓✓ | 9 |
if (cert_store == root_cert_store) { |
1027 |
6 |
cert_store = NewRootCertStore(); |
|
1028 |
6 |
SSL_CTX_set_cert_store(sc->ctx_.get(), cert_store); |
|
1029 |
} |
||
1030 |
9 |
X509_STORE_add_cert(cert_store, ca); |
|
1031 |
9 |
SSL_CTX_add_client_CA(sc->ctx_.get(), ca); |
|
1032 |
} |
||
1033 |
12 |
ret = true; |
|
1034 |
} |
||
1035 |
|||
1036 |
✓✓ | 18 |
if (!ret) { |
1037 |
// TODO(@jasnell): Should this use ThrowCryptoError? |
||
1038 |
6 |
unsigned long err = ERR_get_error(); // NOLINT(runtime/int) |
|
1039 |
6 |
const char* str = ERR_reason_error_string(err); |
|
1040 |
✓✗ | 6 |
str = str != nullptr ? str : "Unknown error"; |
1041 |
|||
1042 |
6 |
return env->ThrowError(str); |
|
1043 |
} |
||
1044 |
} |
||
1045 |
|||
1046 |
#ifndef OPENSSL_NO_ENGINE |
||
1047 |
void SecureContext::SetClientCertEngine( |
||
1048 |
const FunctionCallbackInfo<Value>& args) { |
||
1049 |
Environment* env = Environment::GetCurrent(args); |
||
1050 |
CHECK_EQ(args.Length(), 1); |
||
1051 |
CHECK(args[0]->IsString()); |
||
1052 |
|||
1053 |
SecureContext* sc; |
||
1054 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); |
||
1055 |
|||
1056 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
||
1057 |
|||
1058 |
// SSL_CTX_set_client_cert_engine does not itself support multiple |
||
1059 |
// calls by cleaning up before overwriting the client_cert_engine |
||
1060 |
// internal context variable. |
||
1061 |
// Instead of trying to fix up this problem we in turn also do not |
||
1062 |
// support multiple calls to SetClientCertEngine. |
||
1063 |
CHECK(!sc->client_cert_engine_provided_); |
||
1064 |
|||
1065 |
CryptoErrorStore errors; |
||
1066 |
const Utf8Value engine_id(env->isolate(), args[0]); |
||
1067 |
EnginePointer engine = LoadEngineById(*engine_id, &errors); |
||
1068 |
if (!engine) { |
||
1069 |
Local<Value> exception; |
||
1070 |
if (errors.ToException(env).ToLocal(&exception)) |
||
1071 |
env->isolate()->ThrowException(exception); |
||
1072 |
return; |
||
1073 |
} |
||
1074 |
|||
1075 |
// Note that this takes another reference to `engine`. |
||
1076 |
if (!SSL_CTX_set_client_cert_engine(sc->ctx_.get(), engine.get())) |
||
1077 |
return ThrowCryptoError(env, ERR_get_error()); |
||
1078 |
sc->client_cert_engine_provided_ = true; |
||
1079 |
} |
||
1080 |
#endif // !OPENSSL_NO_ENGINE |
||
1081 |
|||
1082 |
10 |
void SecureContext::GetTicketKeys(const FunctionCallbackInfo<Value>& args) { |
|
1083 |
#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_get_tlsext_ticket_keys) |
||
1084 |
|||
1085 |
SecureContext* wrap; |
||
1086 |
✗✓ | 10 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
1087 |
|||
1088 |
Local<Object> buff; |
||
1089 |
✗✓ | 20 |
if (!Buffer::New(wrap->env(), 48).ToLocal(&buff)) |
1090 |
return; |
||
1091 |
|||
1092 |
10 |
memcpy(Buffer::Data(buff), wrap->ticket_key_name_, 16); |
|
1093 |
10 |
memcpy(Buffer::Data(buff) + 16, wrap->ticket_key_hmac_, 16); |
|
1094 |
10 |
memcpy(Buffer::Data(buff) + 32, wrap->ticket_key_aes_, 16); |
|
1095 |
|||
1096 |
20 |
args.GetReturnValue().Set(buff); |
|
1097 |
#endif // !def(OPENSSL_NO_TLSEXT) && def(SSL_CTX_get_tlsext_ticket_keys) |
||
1098 |
} |
||
1099 |
|||
1100 |
23 |
void SecureContext::SetTicketKeys(const FunctionCallbackInfo<Value>& args) { |
|
1101 |
#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_get_tlsext_ticket_keys) |
||
1102 |
SecureContext* wrap; |
||
1103 |
✗✓ | 23 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
1104 |
|||
1105 |
✗✓ | 23 |
CHECK_GE(args.Length(), 1); // Ticket keys argument is mandatory |
1106 |
✗✓ | 23 |
CHECK(args[0]->IsArrayBufferView()); |
1107 |
46 |
ArrayBufferViewContents<char> buf(args[0].As<ArrayBufferView>()); |
|
1108 |
|||
1109 |
✗✓ | 23 |
CHECK_EQ(buf.length(), 48); |
1110 |
|||
1111 |
23 |
memcpy(wrap->ticket_key_name_, buf.data(), 16); |
|
1112 |
23 |
memcpy(wrap->ticket_key_hmac_, buf.data() + 16, 16); |
|
1113 |
23 |
memcpy(wrap->ticket_key_aes_, buf.data() + 32, 16); |
|
1114 |
|||
1115 |
✓✗ | 46 |
args.GetReturnValue().Set(true); |
1116 |
#endif // !def(OPENSSL_NO_TLSEXT) && def(SSL_CTX_get_tlsext_ticket_keys) |
||
1117 |
} |
||
1118 |
|||
1119 |
void SecureContext::SetFreeListLength(const FunctionCallbackInfo<Value>& args) { |
||
1120 |
} |
||
1121 |
|||
1122 |
// Currently, EnableTicketKeyCallback and TicketKeyCallback are only present for |
||
1123 |
// the regression test in test/parallel/test-https-resume-after-renew.js. |
||
1124 |
1 |
void SecureContext::EnableTicketKeyCallback( |
|
1125 |
const FunctionCallbackInfo<Value>& args) { |
||
1126 |
SecureContext* wrap; |
||
1127 |
✗✓ | 1 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
1128 |
|||
1129 |
1 |
SSL_CTX_set_tlsext_ticket_key_cb(wrap->ctx_.get(), TicketKeyCallback); |
|
1130 |
} |
||
1131 |
|||
1132 |
4 |
int SecureContext::TicketKeyCallback(SSL* ssl, |
|
1133 |
unsigned char* name, |
||
1134 |
unsigned char* iv, |
||
1135 |
EVP_CIPHER_CTX* ectx, |
||
1136 |
HMAC_CTX* hctx, |
||
1137 |
int enc) { |
||
1138 |
static const int kTicketPartSize = 16; |
||
1139 |
|||
1140 |
SecureContext* sc = static_cast<SecureContext*>( |
||
1141 |
4 |
SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl))); |
|
1142 |
|||
1143 |
4 |
Environment* env = sc->env(); |
|
1144 |
8 |
HandleScope handle_scope(env->isolate()); |
|
1145 |
4 |
Context::Scope context_scope(env->context()); |
|
1146 |
|||
1147 |
✓✓ | 16 |
Local<Value> argv[3]; |
1148 |
|||
1149 |
8 |
if (!Buffer::Copy( |
|
1150 |
env, |
||
1151 |
reinterpret_cast<char*>(name), |
||
1152 |
✓✗ | 12 |
kTicketPartSize).ToLocal(&argv[0]) || |
1153 |
✗✓ | 4 |
!Buffer::Copy( |
1154 |
env, |
||
1155 |
reinterpret_cast<char*>(iv), |
||
1156 |
✗✓ | 8 |
kTicketPartSize).ToLocal(&argv[1])) { |
1157 |
return -1; |
||
1158 |
} |
||
1159 |
|||
1160 |
✓✓ | 8 |
argv[2] = enc != 0 ? v8::True(env->isolate()) : v8::False(env->isolate()); |
1161 |
|||
1162 |
Local<Value> ret; |
||
1163 |
8 |
if (!node::MakeCallback( |
|
1164 |
env->isolate(), |
||
1165 |
sc->object(), |
||
1166 |
env->ticketkeycallback_string(), |
||
1167 |
4 |
arraysize(argv), |
|
1168 |
argv, |
||
1169 |
✓✗✗✓ |
12 |
{0, 0}).ToLocal(&ret) || |
1170 |
✗✓ | 4 |
!ret->IsArray()) { |
1171 |
return -1; |
||
1172 |
} |
||
1173 |
4 |
Local<Array> arr = ret.As<Array>(); |
|
1174 |
|||
1175 |
Local<Value> val; |
||
1176 |
✓✗✗✓ |
12 |
if (!arr->Get(env->context(), kTicketKeyReturnIndex).ToLocal(&val) || |
1177 |
✗✓ | 4 |
!val->IsInt32()) { |
1178 |
return -1; |
||
1179 |
} |
||
1180 |
|||
1181 |
4 |
int r = val.As<Int32>()->Value(); |
|
1182 |
✗✓ | 4 |
if (r < 0) |
1183 |
return r; |
||
1184 |
|||
1185 |
Local<Value> hmac; |
||
1186 |
Local<Value> aes; |
||
1187 |
|||
1188 |
4 |
if (!arr->Get(env->context(), kTicketKeyHMACIndex).ToLocal(&hmac) || |
|
1189 |
✓✗✓✗ ✗✓✗✓ |
16 |
!arr->Get(env->context(), kTicketKeyAESIndex).ToLocal(&aes) || |
1190 |
4 |
Buffer::Length(aes) != kTicketPartSize) { |
|
1191 |
return -1; |
||
1192 |
} |
||
1193 |
|||
1194 |
✓✓ | 4 |
if (enc) { |
1195 |
Local<Value> name_val; |
||
1196 |
Local<Value> iv_val; |
||
1197 |
3 |
if (!arr->Get(env->context(), kTicketKeyNameIndex).ToLocal(&name_val) || |
|
1198 |
✓✗✓✗ |
9 |
!arr->Get(env->context(), kTicketKeyIVIndex).ToLocal(&iv_val) || |
1199 |
✓✗✗✓ ✗✓ |
9 |
Buffer::Length(name_val) != kTicketPartSize || |
1200 |
3 |
Buffer::Length(iv_val) != kTicketPartSize) { |
|
1201 |
return -1; |
||
1202 |
} |
||
1203 |
|||
1204 |
3 |
name_val.As<ArrayBufferView>()->CopyContents(name, kTicketPartSize); |
|
1205 |
3 |
iv_val.As<ArrayBufferView>()->CopyContents(iv, kTicketPartSize); |
|
1206 |
} |
||
1207 |
|||
1208 |
4 |
ArrayBufferViewContents<unsigned char> hmac_buf(hmac); |
|
1209 |
8 |
HMAC_Init_ex(hctx, |
|
1210 |
4 |
hmac_buf.data(), |
|
1211 |
4 |
hmac_buf.length(), |
|
1212 |
EVP_sha256(), |
||
1213 |
nullptr); |
||
1214 |
|||
1215 |
4 |
ArrayBufferViewContents<unsigned char> aes_key(aes.As<ArrayBufferView>()); |
|
1216 |
✓✓ | 4 |
if (enc) { |
1217 |
3 |
EVP_EncryptInit_ex(ectx, |
|
1218 |
EVP_aes_128_cbc(), |
||
1219 |
nullptr, |
||
1220 |
aes_key.data(), |
||
1221 |
iv); |
||
1222 |
} else { |
||
1223 |
1 |
EVP_DecryptInit_ex(ectx, |
|
1224 |
EVP_aes_128_cbc(), |
||
1225 |
nullptr, |
||
1226 |
aes_key.data(), |
||
1227 |
iv); |
||
1228 |
} |
||
1229 |
|||
1230 |
4 |
return r; |
|
1231 |
} |
||
1232 |
|||
1233 |
1311 |
int SecureContext::TicketCompatibilityCallback(SSL* ssl, |
|
1234 |
unsigned char* name, |
||
1235 |
unsigned char* iv, |
||
1236 |
EVP_CIPHER_CTX* ectx, |
||
1237 |
HMAC_CTX* hctx, |
||
1238 |
int enc) { |
||
1239 |
SecureContext* sc = static_cast<SecureContext*>( |
||
1240 |
1311 |
SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl))); |
|
1241 |
|||
1242 |
✓✓ | 1311 |
if (enc) { |
1243 |
1251 |
memcpy(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_)); |
|
1244 |
✓✗ | 2502 |
if (RAND_bytes(iv, 16) <= 0 || |
1245 |
1251 |
EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), nullptr, |
|
1246 |
✓✗✗✓ ✗✓ |
2502 |
sc->ticket_key_aes_, iv) <= 0 || |
1247 |
1251 |
HMAC_Init_ex(hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_), |
|
1248 |
EVP_sha256(), nullptr) <= 0) { |
||
1249 |
return -1; |
||
1250 |
} |
||
1251 |
1251 |
return 1; |
|
1252 |
} |
||
1253 |
|||
1254 |
✓✓ | 60 |
if (memcmp(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_)) != 0) { |
1255 |
// The ticket key name does not match. Discard the ticket. |
||
1256 |
12 |
return 0; |
|
1257 |
} |
||
1258 |
|||
1259 |
48 |
if (EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), nullptr, sc->ticket_key_aes_, |
|
1260 |
✓✗✗✓ ✗✓ |
96 |
iv) <= 0 || |
1261 |
48 |
HMAC_Init_ex(hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_), |
|
1262 |
EVP_sha256(), nullptr) <= 0) { |
||
1263 |
return -1; |
||
1264 |
} |
||
1265 |
48 |
return 1; |
|
1266 |
} |
||
1267 |
|||
1268 |
2 |
void SecureContext::CtxGetter(const FunctionCallbackInfo<Value>& info) { |
|
1269 |
SecureContext* sc; |
||
1270 |
✗✓ | 2 |
ASSIGN_OR_RETURN_UNWRAP(&sc, info.This()); |
1271 |
4 |
Local<External> ext = External::New(info.GetIsolate(), sc->ctx_.get()); |
|
1272 |
4 |
info.GetReturnValue().Set(ext); |
|
1273 |
} |
||
1274 |
|||
1275 |
template <bool primary> |
||
1276 |
12 |
void SecureContext::GetCertificate(const FunctionCallbackInfo<Value>& args) { |
|
1277 |
SecureContext* wrap; |
||
1278 |
✗✓ | 12 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
1279 |
12 |
Environment* env = wrap->env(); |
|
1280 |
X509* cert; |
||
1281 |
|||
1282 |
if (primary) |
||
1283 |
6 |
cert = wrap->cert_.get(); |
|
1284 |
else |
||
1285 |
6 |
cert = wrap->issuer_.get(); |
|
1286 |
✗✓ | 12 |
if (cert == nullptr) |
1287 |
return args.GetReturnValue().SetNull(); |
||
1288 |
|||
1289 |
12 |
int size = i2d_X509(cert, nullptr); |
|
1290 |
Local<Object> buff; |
||
1291 |
✗✓ | 24 |
if (!Buffer::New(env, size).ToLocal(&buff)) |
1292 |
return; |
||
1293 |
12 |
unsigned char* serialized = reinterpret_cast<unsigned char*>( |
|
1294 |
12 |
Buffer::Data(buff)); |
|
1295 |
12 |
i2d_X509(cert, &serialized); |
|
1296 |
|||
1297 |
24 |
args.GetReturnValue().Set(buff); |
|
1298 |
} |
||
1299 |
|||
1300 |
namespace { |
||
1301 |
4 |
unsigned long AddCertsFromFile( // NOLINT(runtime/int) |
|
1302 |
X509_STORE* store, |
||
1303 |
const char* file) { |
||
1304 |
4 |
ERR_clear_error(); |
|
1305 |
8 |
MarkPopErrorOnReturn mark_pop_error_on_return; |
|
1306 |
|||
1307 |
8 |
BIOPointer bio(BIO_new_file(file, "r")); |
|
1308 |
✓✓ | 4 |
if (!bio) |
1309 |
1 |
return ERR_get_error(); |
|
1310 |
|||
1311 |
while (X509* x509 = |
||
1312 |
✓✓ | 6 |
PEM_read_bio_X509(bio.get(), nullptr, NoPasswordCallback, nullptr)) { |
1313 |
3 |
X509_STORE_add_cert(store, x509); |
|
1314 |
3 |
X509_free(x509); |
|
1315 |
3 |
} |
|
1316 |
|||
1317 |
3 |
unsigned long err = ERR_peek_error(); // NOLINT(runtime/int) |
|
1318 |
// Ignore error if its EOF/no start line found. |
||
1319 |
✓✗✓✗ ✓✗ |
6 |
if (ERR_GET_LIB(err) == ERR_LIB_PEM && |
1320 |
3 |
ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { |
|
1321 |
3 |
return 0; |
|
1322 |
} |
||
1323 |
|||
1324 |
return err; |
||
1325 |
} |
||
1326 |
} // namespace |
||
1327 |
|||
1328 |
// UseExtraCaCerts is called only once at the start of the Node.js process. |
||
1329 |
4 |
void UseExtraCaCerts(const std::string& file) { |
|
1330 |
4 |
ClearErrorOnReturn clear_error_on_return; |
|
1331 |
|||
1332 |
✓✗ | 4 |
if (root_cert_store == nullptr) { |
1333 |
4 |
root_cert_store = NewRootCertStore(); |
|
1334 |
|||
1335 |
✓✗ | 4 |
if (!file.empty()) { |
1336 |
4 |
unsigned long err = AddCertsFromFile( // NOLINT(runtime/int) |
|
1337 |
root_cert_store, |
||
1338 |
file.c_str()); |
||
1339 |
✓✓ | 4 |
if (err) { |
1340 |
1 |
fprintf(stderr, |
|
1341 |
"Warning: Ignoring extra certs from `%s`, load failed: %s\n", |
||
1342 |
file.c_str(), |
||
1343 |
ERR_error_string(err, nullptr)); |
||
1344 |
} else { |
||
1345 |
3 |
extra_root_certs_loaded = true; |
|
1346 |
} |
||
1347 |
} |
||
1348 |
} |
||
1349 |
4 |
} |
|
1350 |
|||
1351 |
// Exposed to JavaScript strictly for testing purposes. |
||
1352 |
3 |
void IsExtraRootCertsFileLoaded( |
|
1353 |
const FunctionCallbackInfo<Value>& args) { |
||
1354 |
✓✓ | 6 |
return args.GetReturnValue().Set(extra_root_certs_loaded); |
1355 |
} |
||
1356 |
|||
1357 |
} // namespace crypto |
||
1358 |
} // namespace node |
Generated by: GCOVR (Version 4.2) |