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