@@ -221,6 +221,10 @@ using ssize_t = __int64;
221221#endif // NOMINMAX
222222
223223#include < io.h>
224+ #if defined(CPPHTTPLIB_OPENSSL_SUPPORT) && \
225+ !defined (CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)
226+ #define CERT_CHAIN_PARA_HAS_EXTRA_FIELDS
227+ #endif
224228#include < winsock2.h>
225229#include < ws2tcpip.h>
226230
@@ -6309,6 +6313,7 @@ inline bool is_ssl_peer_could_be_closed(SSL *ssl, socket_t sock) {
63096313}
63106314
63116315#ifdef _WIN32
6316+ #ifdef CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
63126317// NOTE: This code came up with the following stackoverflow post:
63136318// https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
63146319inline bool load_system_certs_on_windows (X509_STORE *store) {
@@ -6335,6 +6340,7 @@ inline bool load_system_certs_on_windows(X509_STORE *store) {
63356340
63366341 return result;
63376342}
6343+ #endif // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
63386344#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && TARGET_OS_MAC
63396345template <typename T>
63406346using CFObjectPtr =
@@ -11343,8 +11349,10 @@ inline bool SSLClient::load_certs() {
1134311349 } else {
1134411350 auto loaded = false ;
1134511351#ifdef _WIN32
11352+ #ifdef CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
1134611353 loaded =
1134711354 detail::load_system_certs_on_windows (SSL_CTX_get_cert_store (ctx_));
11355+ #endif // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
1134811356#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && TARGET_OS_MAC
1134911357 loaded = detail::load_system_certs_on_macos (SSL_CTX_get_cert_store (ctx_));
1135011358#endif // _WIN32
@@ -11391,6 +11399,8 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
1139111399 }
1139211400
1139311401 if (verification_status == SSLVerifierResponse::NoDecisionMade) {
11402+ #if !defined(_WIN32) || \
11403+ defined (CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)
1139411404 verify_result_ = SSL_get_verify_result (ssl2);
1139511405
1139611406 if (verify_result_ != X509_V_OK) {
@@ -11399,6 +11409,8 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
1139911409 output_error_log (error, nullptr );
1140011410 return false ;
1140111411 }
11412+ #endif // not _WIN32 ||
11413+ // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
1140211414
1140311415 auto server_cert = SSL_get1_peer_certificate (ssl2);
1140411416 auto se = detail::scope_exit ([&] { X509_free (server_cert); });
@@ -11410,6 +11422,8 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
1141011422 return false ;
1141111423 }
1141211424
11425+ #if !defined(_WIN32) || \
11426+ defined (CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)
1141311427 if (server_hostname_verification_) {
1141411428 if (!verify_host (server_cert)) {
1141511429 last_openssl_error_ = X509_V_ERR_HOSTNAME_MISMATCH;
@@ -11418,6 +11432,87 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
1141811432 return false ;
1141911433 }
1142011434 }
11435+ #else // _WIN32 && !
11436+ // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE Convert
11437+ // OpenSSL certificate to DER format
11438+ auto der_cert =
11439+ std::vector<unsigned char >(i2d_X509 (server_cert, nullptr ));
11440+ auto der_cert_data = der_cert.data ();
11441+ if (i2d_X509 (server_cert, &der_cert_data) < 0 ) {
11442+ error = Error::SSLServerVerification;
11443+ return false ;
11444+ }
11445+
11446+ // Create a certificate context from the DER-encoded certificate
11447+ auto cert_context = CertCreateCertificateContext (
11448+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, der_cert.data (),
11449+ static_cast <DWORD>(der_cert.size ()));
11450+
11451+ if (cert_context == nullptr ) {
11452+ error = Error::SSLServerVerification;
11453+ return false ;
11454+ }
11455+
11456+ auto chain_para = CERT_CHAIN_PARA{};
11457+ chain_para.cbSize = sizeof (chain_para);
11458+ chain_para.dwUrlRetrievalTimeout = 10 * 1000 ;
11459+
11460+ auto chain_context = PCCERT_CHAIN_CONTEXT{};
11461+ auto result = CertGetCertificateChain (
11462+ nullptr , cert_context, nullptr , cert_context->hCertStore ,
11463+ &chain_para,
11464+ CERT_CHAIN_CACHE_END_CERT |
11465+ CERT_CHAIN_REVOCATION_CHECK_END_CERT |
11466+ CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT,
11467+ nullptr , &chain_context);
11468+
11469+ CertFreeCertificateContext (cert_context);
11470+
11471+ if (!result || chain_context == nullptr ) {
11472+ error = Error::SSLServerVerification;
11473+ return false ;
11474+ }
11475+
11476+ // Verify chain policy
11477+ auto extra_policy_para = SSL_EXTRA_CERT_CHAIN_POLICY_PARA{};
11478+ extra_policy_para.cbSize = sizeof (extra_policy_para);
11479+ extra_policy_para.dwAuthType = AUTHTYPE_SERVER;
11480+ auto whost = detail::u8string_to_wstring (host_.c_str ());
11481+ if (server_hostname_verification_) {
11482+ extra_policy_para.pwszServerName =
11483+ const_cast <wchar_t *>(whost.c_str ());
11484+ }
11485+
11486+ auto policy_para = CERT_CHAIN_POLICY_PARA{};
11487+ policy_para.cbSize = sizeof (policy_para);
11488+ policy_para.dwFlags =
11489+ CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS;
11490+ policy_para.pvExtraPolicyPara = &extra_policy_para;
11491+
11492+ auto policy_status = CERT_CHAIN_POLICY_STATUS{};
11493+ policy_status.cbSize = sizeof (policy_status);
11494+
11495+ result = CertVerifyCertificateChainPolicy (
11496+ CERT_CHAIN_POLICY_SSL, chain_context, &policy_para,
11497+ &policy_status);
11498+
11499+ CertFreeCertificateChain (chain_context);
11500+
11501+ if (!result) {
11502+ error = Error::SSLServerVerification;
11503+ return false ;
11504+ }
11505+
11506+ if (policy_status.dwError != 0 ) {
11507+ if (policy_status.dwError == CERT_E_CN_NO_MATCH) {
11508+ error = Error::SSLServerHostnameVerification;
11509+ } else {
11510+ error = Error::SSLServerVerification;
11511+ }
11512+ return false ;
11513+ }
11514+ #endif // not _WIN32 ||
11515+ // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
1142111516 }
1142211517 }
1142311518
0 commit comments