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