@@ -185,6 +185,9 @@ using ssize_t = long;
185185#endif  //  NOMINMAX
186186
187187#include  < io.h> 
188+ #if  defined(CPPHTTPLIB_OPENSSL_SUPPORT)
189+ #define  CERT_CHAIN_PARA_HAS_EXTRA_FIELDS 
190+ #endif 
188191#include  < winsock2.h> 
189192#include  < ws2tcpip.h> 
190193
@@ -5580,34 +5583,7 @@ inline bool is_ssl_peer_could_be_closed(SSL *ssl, socket_t sock) {
55805583         SSL_get_error (ssl, 0 ) == SSL_ERROR_ZERO_RETURN;
55815584}
55825585
5583- #ifdef  _WIN32
5584- //  NOTE: This code came up with the following stackoverflow post:
5585- //  https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
5586- inline  bool  load_system_certs_on_windows (X509_STORE *store) {
5587-   auto  hStore = CertOpenSystemStoreW ((HCRYPTPROV_LEGACY)NULL , L" ROOT"  );
5588-   if  (!hStore) { return  false ; }
5589- 
5590-   auto  result = false ;
5591-   PCCERT_CONTEXT pContext = NULL ;
5592-   while  ((pContext = CertEnumCertificatesInStore (hStore, pContext)) !=
5593-          nullptr ) {
5594-     auto  encoded_cert =
5595-         static_cast <const  unsigned  char  *>(pContext->pbCertEncoded );
5596- 
5597-     auto  x509 = d2i_X509 (NULL , &encoded_cert, pContext->cbCertEncoded );
5598-     if  (x509) {
5599-       X509_STORE_add_cert (store, x509);
5600-       X509_free (x509);
5601-       result = true ;
5602-     }
5603-   }
5604- 
5605-   CertFreeCertificateContext (pContext);
5606-   CertCloseStore (hStore, 0 );
5607- 
5608-   return  result;
5609- }
5610- #elif  defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
5586+ #if  defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
56115587#if  TARGET_OS_OSX
56125588template  <typename  T>
56135589using  CFObjectPtr =
@@ -5697,7 +5673,7 @@ inline bool load_system_certs_on_macos(X509_STORE *store) {
56975673  return  result;
56985674}
56995675#endif  //  TARGET_OS_OSX
5700- #endif  //  _WIN32 
5676+ #endif  //  CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN && __APPLE__ 
57015677#endif  //  CPPHTTPLIB_OPENSSL_SUPPORT
57025678
57035679#ifdef  _WIN32
@@ -9643,14 +9619,11 @@ inline bool SSLClient::load_certs() {
96439619      }
96449620    } else  {
96459621      auto  loaded = false ;
9646- #ifdef  _WIN32
9647-       loaded =
9648-           detail::load_system_certs_on_windows (SSL_CTX_get_cert_store (ctx_));
9649- #elif  defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
9622+ #if  defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
96509623#if  TARGET_OS_OSX
96519624      loaded = detail::load_system_certs_on_macos (SSL_CTX_get_cert_store (ctx_));
96529625#endif  //  TARGET_OS_OSX
9653- #endif  //  _WIN32 
9626+ #endif  //  CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN && __APPLE__ 
96549627      if  (!loaded) { SSL_CTX_set_default_verify_paths (ctx_); }
96559628    }
96569629  });
@@ -9690,12 +9663,14 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
96909663          }
96919664
96929665          if  (verification_status == SSLVerifierResponse::NoDecisionMade) {
9666+ #ifndef  _WIN32
96939667            verify_result_ = SSL_get_verify_result (ssl2);
96949668
96959669            if  (verify_result_ != X509_V_OK) {
96969670              error = Error::SSLServerVerification;
96979671              return  false ;
96989672            }
9673+ #endif 
96999674
97009675            auto  server_cert = SSL_get1_peer_certificate (ssl2);
97019676            auto  se = detail::scope_exit ([&] { X509_free (server_cert); });
@@ -9705,12 +9680,92 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
97059680              return  false ;
97069681            }
97079682
9683+ #ifdef  _WIN32
9684+             //  Convert OpenSSL certificate to DER format
9685+             auto  der_cert =
9686+                 std::vector<unsigned  char >(i2d_X509 (server_cert, nullptr ));
9687+             auto  der_cert_data = der_cert.data ();
9688+             if  (i2d_X509 (server_cert, &der_cert_data) < 0 ) {
9689+               error = Error::SSLServerVerification;
9690+               return  false ;
9691+             }
9692+ 
9693+             //  Create a certificate context from the DER-encoded certificate
9694+             auto  cert_context = CertCreateCertificateContext (
9695+                 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, der_cert.data (),
9696+                 static_cast <DWORD>(der_cert.size ()));
9697+ 
9698+             if  (cert_context == nullptr ) {
9699+               error = Error::SSLServerVerification;
9700+               return  false ;
9701+             }
9702+ 
9703+             auto  chain_para = CERT_CHAIN_PARA{};
9704+             chain_para.cbSize  = sizeof (chain_para);
9705+             chain_para.dwUrlRetrievalTimeout  = 10  * 1000 ;
9706+ 
9707+             auto  chain_context = PCCERT_CHAIN_CONTEXT{};
9708+             auto  result = CertGetCertificateChain (
9709+                 nullptr , cert_context, nullptr , cert_context->hCertStore ,
9710+                 &chain_para,
9711+                 CERT_CHAIN_CACHE_END_CERT |
9712+                     CERT_CHAIN_REVOCATION_CHECK_END_CERT |
9713+                     CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT,
9714+                 nullptr , &chain_context);
9715+ 
9716+             CertFreeCertificateContext (cert_context);
9717+ 
9718+             if  (!result || chain_context == nullptr ) {
9719+               error = Error::SSLServerVerification;
9720+               return  false ;
9721+             }
9722+ 
9723+             //  Verify chain policy
9724+             auto  extra_policy_para = SSL_EXTRA_CERT_CHAIN_POLICY_PARA{};
9725+             extra_policy_para.cbSize  = sizeof (extra_policy_para);
9726+             extra_policy_para.dwAuthType  = AUTHTYPE_SERVER;
9727+             auto  whost = detail::u8string_to_wstring (host_.c_str ());
9728+             if  (server_hostname_verification_) {
9729+               extra_policy_para.pwszServerName  =
9730+                   const_cast <wchar_t  *>(whost.c_str ());
9731+             }
9732+ 
9733+             auto  policy_para = CERT_CHAIN_POLICY_PARA{};
9734+             policy_para.cbSize  = sizeof (policy_para);
9735+             policy_para.dwFlags  =
9736+                 CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS;
9737+             policy_para.pvExtraPolicyPara  = &extra_policy_para;
9738+ 
9739+             auto  policy_status = CERT_CHAIN_POLICY_STATUS{};
9740+             policy_status.cbSize  = sizeof (policy_status);
9741+ 
9742+             result = CertVerifyCertificateChainPolicy (
9743+                 CERT_CHAIN_POLICY_SSL, chain_context, &policy_para,
9744+                 &policy_status);
9745+ 
9746+             CertFreeCertificateChain (chain_context);
9747+ 
9748+             if  (!result) {
9749+               error = Error::SSLServerVerification;
9750+               return  false ;
9751+             }
9752+ 
9753+             if  (policy_status.dwError  != 0 ) {
9754+               if  (policy_status.dwError  == CERT_E_CN_NO_MATCH) {
9755+                 error = Error::SSLServerHostnameVerification;
9756+               } else  {
9757+                 error = Error::SSLServerVerification;
9758+               }
9759+               return  false ;
9760+             }
9761+ #else 
97089762            if  (server_hostname_verification_) {
97099763              if  (!verify_host (server_cert)) {
97109764                error = Error::SSLServerHostnameVerification;
97119765                return  false ;
97129766              }
97139767            }
9768+ #endif 
97149769          }
97159770        }
97169771
0 commit comments