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