@@ -239,7 +239,10 @@ using socket_t = int;
239
239
#pragma comment(lib, "crypt32.lib")
240
240
#pragma comment(lib, "cryptui.lib")
241
241
#endif
242
- #endif // _WIN32
242
+ #elif defined(__APPLE__) // _WIN32
243
+ #include < CoreFoundation/CoreFoundation.h>
244
+ #include < Security/Security.h>
245
+ #endif // __APPLE__
243
246
244
247
#include < openssl/err.h>
245
248
#include < openssl/evp.h>
@@ -4388,15 +4391,15 @@ inline std::string SHA_512(const std::string &s) {
4388
4391
}
4389
4392
#endif
4390
4393
4391
- #ifdef _WIN32
4392
4394
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
4395
+ #ifdef _WIN32
4393
4396
// NOTE: This code came up with the following stackoverflow post:
4394
4397
// https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
4395
4398
inline bool load_system_certs_on_windows (X509_STORE *store) {
4396
4399
auto hStore = CertOpenSystemStoreW ((HCRYPTPROV_LEGACY)NULL , L" ROOT" );
4397
-
4398
4400
if (!hStore) { return false ; }
4399
4401
4402
+ auto result = false ;
4400
4403
PCCERT_CONTEXT pContext = NULL ;
4401
4404
while ((pContext = CertEnumCertificatesInStore (hStore, pContext)) !=
4402
4405
nullptr ) {
@@ -4407,16 +4410,107 @@ inline bool load_system_certs_on_windows(X509_STORE *store) {
4407
4410
if (x509) {
4408
4411
X509_STORE_add_cert (store, x509);
4409
4412
X509_free (x509);
4413
+ result = true ;
4410
4414
}
4411
4415
}
4412
4416
4413
4417
CertFreeCertificateContext (pContext);
4414
4418
CertCloseStore (hStore, 0 );
4415
4419
4420
+ return result;
4421
+ }
4422
+ #elif defined(__APPLE__)
4423
+ template <typename T>
4424
+ using CFObjectPtr =
4425
+ std::unique_ptr<typename std::remove_pointer<T>::type, void (*)(CFTypeRef)>;
4426
+
4427
+ inline void cf_object_ptr_deleter (CFTypeRef obj) {
4428
+ if (obj) { CFRelease (obj); }
4429
+ }
4430
+
4431
+ inline bool retrieve_certs_from_keychain (CFObjectPtr<CFArrayRef> &certs) {
4432
+ CFStringRef keys[] = {kSecClass , kSecMatchLimit , kSecReturnRef };
4433
+ CFTypeRef values[] = {kSecClassCertificate , kSecMatchLimitAll ,
4434
+ kCFBooleanTrue };
4435
+
4436
+ CFObjectPtr<CFDictionaryRef> query (
4437
+ CFDictionaryCreate (nullptr , reinterpret_cast <const void **>(keys), values,
4438
+ sizeof (keys) / sizeof (keys[0 ]),
4439
+ &kCFTypeDictionaryKeyCallBacks ,
4440
+ &kCFTypeDictionaryValueCallBacks ),
4441
+ cf_object_ptr_deleter);
4442
+
4443
+ if (!query) { return false ; }
4444
+
4445
+ CFTypeRef security_items = nullptr ;
4446
+ if (SecItemCopyMatching (query.get (), &security_items) != errSecSuccess ||
4447
+ CFArrayGetTypeID () != CFGetTypeID (security_items)) {
4448
+ return false ;
4449
+ }
4450
+
4451
+ certs.reset (reinterpret_cast <CFArrayRef>(security_items));
4452
+ return true ;
4453
+ }
4454
+
4455
+ inline bool retrieve_root_certs_from_keychain (CFObjectPtr<CFArrayRef> &certs) {
4456
+ CFArrayRef root_security_items = nullptr ;
4457
+ if (SecTrustCopyAnchorCertificates (&root_security_items) != errSecSuccess) {
4458
+ return false ;
4459
+ }
4460
+
4461
+ certs.reset (root_security_items);
4416
4462
return true ;
4417
4463
}
4464
+
4465
+ inline bool add_certs_to_x509_store (CFArrayRef certs, X509_STORE *store) {
4466
+ auto result = false ;
4467
+ for (int i = 0 ; i < CFArrayGetCount (certs); ++i) {
4468
+ const auto cert = reinterpret_cast <const __SecCertificate *>(
4469
+ CFArrayGetValueAtIndex (certs, i));
4470
+
4471
+ if (SecCertificateGetTypeID () != CFGetTypeID (cert)) { continue ; }
4472
+
4473
+ CFDataRef cert_data = nullptr ;
4474
+ if (SecItemExport (cert, kSecFormatX509Cert , 0 , nullptr , &cert_data) !=
4475
+ errSecSuccess) {
4476
+ continue ;
4477
+ }
4478
+
4479
+ CFObjectPtr<CFDataRef> cert_data_ptr (cert_data, cf_object_ptr_deleter);
4480
+
4481
+ auto encoded_cert = static_cast <const unsigned char *>(
4482
+ CFDataGetBytePtr (cert_data_ptr.get ()));
4483
+
4484
+ auto x509 =
4485
+ d2i_X509 (NULL , &encoded_cert, CFDataGetLength (cert_data_ptr.get ()));
4486
+
4487
+ if (x509) {
4488
+ X509_STORE_add_cert (store, x509);
4489
+ X509_free (x509);
4490
+ result = true ;
4491
+ }
4492
+ }
4493
+
4494
+ return result;
4495
+ }
4496
+
4497
+ inline bool load_system_certs_on_apple (X509_STORE *store) {
4498
+ auto result = false ;
4499
+ CFObjectPtr<CFArrayRef> certs (nullptr , cf_object_ptr_deleter);
4500
+ if (retrieve_certs_from_keychain (certs) && certs) {
4501
+ result = add_certs_to_x509_store (certs.get (), store);
4502
+ }
4503
+
4504
+ if (retrieve_root_certs_from_keychain (certs) && certs) {
4505
+ result = add_certs_to_x509_store (certs.get (), store) || result;
4506
+ }
4507
+
4508
+ return result;
4509
+ }
4510
+ #endif
4418
4511
#endif
4419
4512
4513
+ #ifdef _WIN32
4420
4514
class WSInit {
4421
4515
public:
4422
4516
WSInit () {
@@ -7842,11 +7936,14 @@ inline bool SSLClient::load_certs() {
7842
7936
ret = false ;
7843
7937
}
7844
7938
} else {
7939
+ auto loaded = false ;
7845
7940
#ifdef _WIN32
7846
- detail::load_system_certs_on_windows (SSL_CTX_get_cert_store (ctx_));
7847
- #else
7848
- SSL_CTX_set_default_verify_paths (ctx_);
7941
+ loaded =
7942
+ detail::load_system_certs_on_windows (SSL_CTX_get_cert_store (ctx_));
7943
+ #elif defined(__APPLE__)
7944
+ loaded = detail::load_system_certs_on_apple (SSL_CTX_get_cert_store (ctx_));
7849
7945
#endif
7946
+ if (!loaded) { SSL_CTX_set_default_verify_paths (ctx_); }
7850
7947
}
7851
7948
});
7852
7949
0 commit comments