18
18
#ifndef OPENSSL_NO_ENGINE
19
19
#include < openssl/engine.h>
20
20
#endif // !OPENSSL_NO_ENGINE
21
+ #ifdef __APPLE__
22
+ #include < CoreFoundation/CoreFoundation.h>
23
+ #include < Security/Security.h>
24
+ #endif
25
+
21
26
22
27
namespace node {
23
28
@@ -222,6 +227,277 @@ unsigned long LoadCertsFromFile( // NOLINT(runtime/int)
222
227
}
223
228
}
224
229
230
+ enum TrustStatus { UNSPECIFIED, TRUSTED, DISTRUSTED };
231
+
232
+ std::string stdStringFromCF (CFStringRef s) {
233
+ if (auto fastCString = CFStringGetCStringPtr (s, kCFStringEncodingUTF8 )) {
234
+ return std::string (fastCString);
235
+ }
236
+ auto utf16length = CFStringGetLength (s);
237
+ auto maxUtf8len = CFStringGetMaximumSizeForEncoding (utf16length,
238
+ kCFStringEncodingUTF8 );
239
+ std::string converted (maxUtf8len, ' \0 ' );
240
+
241
+ CFStringGetCString (s, converted.data (), maxUtf8len, kCFStringEncodingUTF8 );
242
+ converted.resize (std::strlen (converted.data ()));
243
+
244
+ return converted;
245
+ }
246
+
247
+ std::string getCertIssuer (X509* cert) {
248
+ ClearErrorOnReturn clearErrorOnReturn;
249
+ if (cert == nullptr ) return {};
250
+ BIO* bio = BIO_new (BIO_s_mem ());
251
+ if (bio == nullptr ) {
252
+ return nullptr ;
253
+ }
254
+ if (X509_NAME_print_ex (
255
+ bio, X509_get_issuer_name (cert), 0 , XN_FLAG_ONELINE) <=
256
+ 0 ) {
257
+ return {};
258
+ }
259
+
260
+ const int resultLen = BIO_pending (bio);
261
+ char * issuer = reinterpret_cast <char *>(calloc (resultLen + 1 , 1 ));
262
+ BIO_read (bio, issuer, resultLen);
263
+ BIO_free_all (bio);
264
+
265
+ std::string str (issuer);
266
+ return str;
267
+ }
268
+
269
+ std::string getCertSubject (X509* cert) {
270
+ ClearErrorOnReturn clearErrorOnReturn;
271
+ if (cert == nullptr ) return {};
272
+ BIO* bio = BIO_new (BIO_s_mem ());
273
+ if (bio == nullptr ) {
274
+ return nullptr ;
275
+ }
276
+ if (X509_NAME_print_ex (
277
+ bio, X509_get_subject_name (cert), 0 , XN_FLAG_ONELINE) <=
278
+ 0 ) {
279
+ return {};
280
+ }
281
+
282
+ const int resultLen = BIO_pending (bio);
283
+ char * issuer = reinterpret_cast <char *>(calloc (resultLen + 1 , 1 ));
284
+ BIO_read (bio, issuer, resultLen);
285
+ BIO_free_all (bio);
286
+
287
+ std::string str (issuer);
288
+ return str;
289
+ }
290
+
291
+ bool IsSelfSigned (X509* cert) {
292
+ auto issuerName = getCertIssuer (cert);
293
+ auto subjectName = getCertSubject (cert);
294
+
295
+ if (issuerName == subjectName) {
296
+ // fprintf(stderr, "Self signed\n");
297
+ return true ;
298
+ } else {
299
+ // fprintf(stderr, "NOT Self signed\n");
300
+ return false ;
301
+ }
302
+ }
303
+
304
+ enum TrustStatus IsTrustDictionaryTrustedForPolicy (
305
+ CFDictionaryRef trust_dict
306
+ ) {
307
+ // Trust settings may be scoped to a single application
308
+ // skip as this is not supported
309
+ if (CFDictionaryContainsKey (trust_dict, kSecTrustSettingsApplication )) {
310
+ return UNSPECIFIED;
311
+ }
312
+
313
+ // Trust settings may be scoped using policy-specific constraints. For
314
+ // example, SSL trust settings might be scoped to a single hostname, or EAP
315
+ // settings specific to a particular WiFi network.
316
+ // As this is not presently supported, skip any policy-specific trust
317
+ // settings.
318
+ if (CFDictionaryContainsKey (trust_dict, kSecTrustSettingsPolicyString )) {
319
+ return UNSPECIFIED;
320
+ }
321
+
322
+ int trust_settings_result = kSecTrustSettingsResultTrustRoot ;
323
+ if (CFDictionaryContainsKey (trust_dict, kSecTrustSettingsResult )) {
324
+ CFNumberRef trust_settings_result_ref = (CFNumberRef) CFDictionaryGetValue (
325
+ trust_dict, kSecTrustSettingsResult );
326
+
327
+ CFNumberGetValue (trust_settings_result_ref, kCFNumberIntType ,
328
+ &trust_settings_result);
329
+
330
+ if (!trust_settings_result_ref) {
331
+ return UNSPECIFIED;
332
+ }
333
+
334
+ if (trust_settings_result == kSecTrustSettingsResultDeny ) {
335
+ // fprintf(stderr, "Returning distrusted\n");
336
+ return DISTRUSTED;
337
+ }
338
+ // fprintf(stderr, "Checking if matches trust root\n");
339
+ return trust_settings_result == kSecTrustSettingsResultTrustRoot ||
340
+ trust_settings_result == kSecTrustSettingsResultTrustAsRoot ?
341
+ TRUSTED : UNSPECIFIED;
342
+ }
343
+
344
+ return UNSPECIFIED;
345
+ }
346
+
347
+ bool IsTrustSettingsTrustedForPolicy (CFArrayRef trustSettings,
348
+ bool isSelfIssued) {
349
+ // The trustSettings parameter can return a valid but empty CFArrayRef.
350
+ // This empty trust-settings array means “always trust this certificate”
351
+ // with an overall trust setting for the certificate of
352
+ // kSecTrustSettingsResultTrustRoot
353
+ if (CFArrayGetCount (trustSettings) == 0 ) {
354
+ if (isSelfIssued) {
355
+ return true ;
356
+ }
357
+ }
358
+
359
+ CFIndex trustSettingsCount = CFArrayGetCount (trustSettings);
360
+
361
+ for (CFIndex i = 0 ; i < trustSettingsCount ; ++i) {
362
+ CFDictionaryRef trustDict = (CFDictionaryRef) CFArrayGetValueAtIndex (
363
+ trustSettings, i);
364
+
365
+ enum TrustStatus trust = IsTrustDictionaryTrustedForPolicy (trustDict);
366
+
367
+ if (trust == DISTRUSTED) {
368
+ return false ;
369
+ } else if (trust == TRUSTED) {
370
+ return true ;
371
+ }
372
+ }
373
+ return false ;
374
+ }
375
+
376
+ bool IsCertificateTrustValid (SecCertificateRef ref) {
377
+ SecTrustRef secTrust = nullptr ;
378
+ CFMutableArrayRef subjCerts = CFArrayCreateMutable (
379
+ nullptr , 1 , &kCFTypeArrayCallBacks );
380
+ CFArraySetValueAtIndex (subjCerts, 0 , ref);
381
+
382
+ SecPolicyRef policy = SecPolicyCreateBasicX509 ();
383
+ OSStatus ortn = SecTrustCreateWithCertificates (subjCerts, policy, &secTrust);
384
+ bool result = false ;
385
+ if (ortn) {
386
+ /* should never happen */
387
+ goto errOut;
388
+ }
389
+
390
+ result = SecTrustEvaluateWithError (secTrust, nullptr );
391
+ // fprintf(stderr, "Validation result: %s\n", result ? "true" : "false");
392
+ errOut:
393
+ if (policy) {
394
+ CFRelease (policy);
395
+ }
396
+ if (secTrust) {
397
+ CFRelease (secTrust);
398
+ }
399
+ if (subjCerts) {
400
+ CFRelease (subjCerts);
401
+ }
402
+ return result;
403
+ }
404
+
405
+ bool IsCertificateTrustedForPolicy (X509* cert, SecCertificateRef ref) {
406
+ OSStatus err;
407
+
408
+ for (const auto & trust_domain :
409
+ {kSecTrustSettingsDomainUser , kSecTrustSettingsDomainAdmin }) {
410
+ CFArrayRef trustSettings;
411
+ err = SecTrustSettingsCopyTrustSettings (ref, trust_domain, &trustSettings);
412
+
413
+ bool isSelfSigned = IsSelfSigned (cert);
414
+
415
+ if (err == errSecSuccess && trustSettings != nullptr ) {
416
+ return IsTrustSettingsTrustedForPolicy (trustSettings, isSelfSigned);
417
+ }
418
+
419
+ // An empty trust settings array isn’t the same as no trust settings,
420
+ // where the trustSettings parameter returns NULL.
421
+ // No trust-settings array means
422
+ // “this certificate must be verifiable using a known trusted certificate”.
423
+ if (trustSettings == nullptr ) {
424
+ return IsCertificateTrustValid (ref);
425
+ }
426
+ }
427
+ return false ;
428
+ }
429
+
430
+ void ReadMacOSKeychainCertificates (
431
+ std::vector<std::string>* system_root_certificates) {
432
+ CFTypeRef searchKeys[] = { kSecClass , kSecMatchLimit , kSecReturnRef };
433
+ CFTypeRef searchValues[] = {
434
+ kSecClassCertificate , kSecMatchLimitAll , kCFBooleanTrue };
435
+ CFDictionaryRef search = CFDictionaryCreate (
436
+ kCFAllocatorDefault , searchKeys, searchValues, 3 ,
437
+ &kCFTypeDictionaryKeyCallBacks , &kCFTypeDictionaryValueCallBacks );
438
+
439
+ CFArrayRef currAnchors = nullptr ;
440
+ OSStatus ortn = SecItemCopyMatching (
441
+ search,
442
+ reinterpret_cast <CFTypeRef *>(&currAnchors));
443
+
444
+ if (ortn) {
445
+ fprintf (stderr, " Failed: %d\n " , ortn);
446
+ }
447
+
448
+ CFIndex count = CFArrayGetCount (currAnchors);
449
+
450
+ std::vector<X509*> system_root_certificates_X509;
451
+ for (int i = 0 ; i < count ; ++i) {
452
+ SecCertificateRef certRef = (SecCertificateRef) CFArrayGetValueAtIndex (
453
+ currAnchors, i);
454
+
455
+ CFStringRef certSummary = SecCertificateCopySubjectSummary (certRef);
456
+ std::string stdCertSummary = stdStringFromCF (certSummary);
457
+
458
+ CFDataRef derData = SecCertificateCopyData (certRef);
459
+ if (!derData) {
460
+ fprintf (stderr, " ERROR: SecCertificateCopyData failed\n " );
461
+ continue ;
462
+ }
463
+ auto dataBufferPointer = CFDataGetBytePtr (derData);
464
+
465
+ X509* cert =
466
+ d2i_X509 (nullptr , &dataBufferPointer, CFDataGetLength (derData));
467
+ CFRelease (derData);
468
+ bool isValid = IsCertificateTrustedForPolicy (cert, certRef);
469
+ if (isValid) {
470
+ system_root_certificates_X509.emplace_back (cert);
471
+ }
472
+ }
473
+
474
+
475
+ for (size_t i = 0 ; i < system_root_certificates_X509.size (); i++) {
476
+ BIOPointer bio (BIO_new (BIO_s_mem ()));
477
+ CHECK (bio);
478
+
479
+ BUF_MEM* mem = nullptr ;
480
+ int result = PEM_write_bio_X509 (bio.get (),
481
+ system_root_certificates_X509[i]);
482
+ if (!result) {
483
+ fprintf (stderr, " Warning: PEM_write_bio_X509 failed with: %d" , result);
484
+ continue ;
485
+ }
486
+
487
+ BIO_get_mem_ptr (bio.get (), &mem);
488
+ std::string certificate_string_pem (mem->data , mem->length );
489
+
490
+ system_root_certificates->emplace_back (certificate_string_pem);
491
+ }
492
+ }
493
+
494
+ void ReadSystemStoreCertificates (
495
+ std::vector<std::string>* system_root_certificates) {
496
+ #ifdef __APPLE__
497
+ ReadMacOSKeychainCertificates (system_root_certificates);
498
+ #endif
499
+ }
500
+
225
501
X509_STORE* NewRootCertStore () {
226
502
static std::vector<X509*> root_certs_vector;
227
503
static bool root_certs_vector_loaded = false ;
@@ -230,9 +506,21 @@ X509_STORE* NewRootCertStore() {
230
506
231
507
if (!root_certs_vector_loaded) {
232
508
if (per_process::cli_options->ssl_openssl_cert_store == false ) {
509
+ std::vector<std::string> combined_root_certs;
510
+
511
+ for (size_t i = 0 ; i < arraysize (root_certs); i++) {
512
+ combined_root_certs.emplace_back (root_certs[i]);
513
+ }
514
+
515
+ if (per_process::cli_options->use_system_ca ) {
516
+ ReadSystemStoreCertificates (&combined_root_certs);
517
+ }
518
+
233
519
for (size_t i = 0 ; i < arraysize (root_certs); i++) {
234
520
X509* x509 = PEM_read_bio_X509 (
235
- NodeBIO::NewFixed (root_certs[i], strlen (root_certs[i])).get (),
521
+ NodeBIO::NewFixed (combined_root_certs[i].data (),
522
+ combined_root_certs[i].length ())
523
+ .get (),
236
524
nullptr , // no re-use of X509 structure
237
525
NoPasswordCallback,
238
526
nullptr ); // no callback data
@@ -282,19 +570,31 @@ X509_STORE* NewRootCertStore() {
282
570
283
571
void GetRootCertificates (const FunctionCallbackInfo<Value>& args) {
284
572
Environment* env = Environment::GetCurrent (args);
285
- Local<Value> result[ arraysize (root_certs)] ;
573
+ std::vector<std::string> combined_root_certs ;
286
574
287
575
for (size_t i = 0 ; i < arraysize (root_certs); i++) {
576
+ combined_root_certs.emplace_back (root_certs[i]);
577
+ }
578
+
579
+ if (per_process::cli_options->use_system_ca ) {
580
+ ReadSystemStoreCertificates (&combined_root_certs);
581
+ }
582
+
583
+ std::vector<Local<Value>> result (combined_root_certs.size ());
584
+
585
+ for (size_t i = 0 ; i < combined_root_certs.size (); i++) {
288
586
if (!String::NewFromOneByte (
289
587
env->isolate (),
290
- reinterpret_cast <const uint8_t *>(root_certs[i]))
291
- .ToLocal (&result[i])) {
588
+ reinterpret_cast <const uint8_t *>(combined_root_certs[i].data ()),
589
+ v8::NewStringType::kNormal ,
590
+ combined_root_certs[i].size ())
591
+ .ToLocal (&result[i])) {
292
592
return ;
293
593
}
294
594
}
295
595
296
596
args.GetReturnValue ().Set (
297
- Array::New (env->isolate (), result, arraysize (root_certs )));
597
+ Array::New (env->isolate (), result. data (), combined_root_certs. size ( )));
298
598
}
299
599
300
600
bool SecureContext::HasInstance (Environment* env, const Local<Value>& value) {
0 commit comments