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