@@ -197,6 +197,9 @@ using ssize_t = long;
197197#endif // NOMINMAX
198198
199199#include < io.h>
200+ #if defined(CPPHTTPLIB_OPENSSL_SUPPORT) && ! defined(CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)
201+ #define CERT_CHAIN_PARA_HAS_EXTRA_FIELDS
202+ #endif
200203#include < winsock2.h>
201204#include < ws2tcpip.h>
202205
@@ -6040,6 +6043,7 @@ inline bool is_ssl_peer_could_be_closed(SSL *ssl, socket_t sock) {
60406043}
60416044
60426045#ifdef _WIN32
6046+ #ifdef CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
60436047// NOTE: This code came up with the following stackoverflow post:
60446048// https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
60456049inline bool load_system_certs_on_windows (X509_STORE *store) {
@@ -6066,6 +6070,7 @@ inline bool load_system_certs_on_windows(X509_STORE *store) {
60666070
60676071 return result;
60686072}
6073+ #endif // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
60696074#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && \
60706075 defined (TARGET_OS_OSX)
60716076template <typename T>
@@ -10483,8 +10488,10 @@ inline bool SSLClient::load_certs() {
1048310488 } else {
1048410489 auto loaded = false ;
1048510490#ifdef _WIN32
10491+ #ifdef CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
1048610492 loaded =
1048710493 detail::load_system_certs_on_windows (SSL_CTX_get_cert_store (ctx_));
10494+ #endif // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
1048810495#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && \
1048910496 defined (TARGET_OS_OSX)
1049010497 loaded = detail::load_system_certs_on_macos (SSL_CTX_get_cert_store (ctx_));
@@ -10529,13 +10536,15 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
1052910536 }
1053010537
1053110538 if (verification_status == SSLVerifierResponse::NoDecisionMade) {
10539+ #if ! defined(_WIN32) || defined(CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)
1053210540 verify_result_ = SSL_get_verify_result (ssl2);
1053310541
1053410542 if (verify_result_ != X509_V_OK) {
1053510543 last_openssl_error_ = static_cast <unsigned long >(verify_result_);
1053610544 error = Error::SSLServerVerification;
1053710545 return false ;
1053810546 }
10547+ #endif // not _WIN32 || CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
1053910548
1054010549 auto server_cert = SSL_get1_peer_certificate (ssl2);
1054110550 auto se = detail::scope_exit ([&] { X509_free (server_cert); });
@@ -10546,13 +10555,93 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
1054610555 return false ;
1054710556 }
1054810557
10558+ #if ! defined(_WIN32) || defined(CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)
1054910559 if (server_hostname_verification_) {
1055010560 if (!verify_host (server_cert)) {
1055110561 last_openssl_error_ = X509_V_ERR_HOSTNAME_MISMATCH;
1055210562 error = Error::SSLServerHostnameVerification;
1055310563 return false ;
1055410564 }
1055510565 }
10566+ #else // _WIN32 && ! CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
10567+ // Convert OpenSSL certificate to DER format
10568+ auto der_cert =
10569+ std::vector<unsigned char >(i2d_X509 (server_cert, nullptr ));
10570+ auto der_cert_data = der_cert.data ();
10571+ if (i2d_X509 (server_cert, &der_cert_data) < 0 ) {
10572+ error = Error::SSLServerVerification;
10573+ return false ;
10574+ }
10575+
10576+ // Create a certificate context from the DER-encoded certificate
10577+ auto cert_context = CertCreateCertificateContext (
10578+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, der_cert.data (),
10579+ static_cast <DWORD>(der_cert.size ()));
10580+
10581+ if (cert_context == nullptr ) {
10582+ error = Error::SSLServerVerification;
10583+ return false ;
10584+ }
10585+
10586+ auto chain_para = CERT_CHAIN_PARA{};
10587+ chain_para.cbSize = sizeof (chain_para);
10588+ chain_para.dwUrlRetrievalTimeout = 10 * 1000 ;
10589+
10590+ auto chain_context = PCCERT_CHAIN_CONTEXT{};
10591+ auto result = CertGetCertificateChain (
10592+ nullptr , cert_context, nullptr , cert_context->hCertStore ,
10593+ &chain_para,
10594+ CERT_CHAIN_CACHE_END_CERT |
10595+ CERT_CHAIN_REVOCATION_CHECK_END_CERT |
10596+ CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT,
10597+ nullptr , &chain_context);
10598+
10599+ CertFreeCertificateContext (cert_context);
10600+
10601+ if (!result || chain_context == nullptr ) {
10602+ error = Error::SSLServerVerification;
10603+ return false ;
10604+ }
10605+
10606+ // Verify chain policy
10607+ auto extra_policy_para = SSL_EXTRA_CERT_CHAIN_POLICY_PARA{};
10608+ extra_policy_para.cbSize = sizeof (extra_policy_para);
10609+ extra_policy_para.dwAuthType = AUTHTYPE_SERVER;
10610+ auto whost = detail::u8string_to_wstring (host_.c_str ());
10611+ if (server_hostname_verification_) {
10612+ extra_policy_para.pwszServerName =
10613+ const_cast <wchar_t *>(whost.c_str ());
10614+ }
10615+
10616+ auto policy_para = CERT_CHAIN_POLICY_PARA{};
10617+ policy_para.cbSize = sizeof (policy_para);
10618+ policy_para.dwFlags =
10619+ CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS;
10620+ policy_para.pvExtraPolicyPara = &extra_policy_para;
10621+
10622+ auto policy_status = CERT_CHAIN_POLICY_STATUS{};
10623+ policy_status.cbSize = sizeof (policy_status);
10624+
10625+ result = CertVerifyCertificateChainPolicy (
10626+ CERT_CHAIN_POLICY_SSL, chain_context, &policy_para,
10627+ &policy_status);
10628+
10629+ CertFreeCertificateChain (chain_context);
10630+
10631+ if (!result) {
10632+ error = Error::SSLServerVerification;
10633+ return false ;
10634+ }
10635+
10636+ if (policy_status.dwError != 0 ) {
10637+ if (policy_status.dwError == CERT_E_CN_NO_MATCH) {
10638+ error = Error::SSLServerHostnameVerification;
10639+ } else {
10640+ error = Error::SSLServerVerification;
10641+ }
10642+ return false ;
10643+ }
10644+ #endif // not _WIN32 || CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
1055610645 }
1055710646 }
1055810647
0 commit comments