@@ -197,6 +197,10 @@ using ssize_t = long;
197197#endif // NOMINMAX
198198
199199#include < io.h>
200+ #if defined(CPPHTTPLIB_OPENSSL_SUPPORT) && \
201+ !defined (CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)
202+ #define CERT_CHAIN_PARA_HAS_EXTRA_FIELDS
203+ #endif
200204#include < winsock2.h>
201205#include < ws2tcpip.h>
202206
@@ -6040,6 +6044,7 @@ inline bool is_ssl_peer_could_be_closed(SSL *ssl, socket_t sock) {
60406044}
60416045
60426046#ifdef _WIN32
6047+ #ifdef CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
60436048// NOTE: This code came up with the following stackoverflow post:
60446049// https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
60456050inline bool load_system_certs_on_windows (X509_STORE *store) {
@@ -6066,6 +6071,7 @@ inline bool load_system_certs_on_windows(X509_STORE *store) {
60666071
60676072 return result;
60686073}
6074+ #endif // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
60696075#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && \
60706076 defined (TARGET_OS_OSX)
60716077template <typename T>
@@ -10483,8 +10489,10 @@ inline bool SSLClient::load_certs() {
1048310489 } else {
1048410490 auto loaded = false ;
1048510491#ifdef _WIN32
10492+ #ifdef CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
1048610493 loaded =
1048710494 detail::load_system_certs_on_windows (SSL_CTX_get_cert_store (ctx_));
10495+ #endif // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
1048810496#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && \
1048910497 defined (TARGET_OS_OSX)
1049010498 loaded = detail::load_system_certs_on_macos (SSL_CTX_get_cert_store (ctx_));
@@ -10529,13 +10537,17 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
1052910537 }
1053010538
1053110539 if (verification_status == SSLVerifierResponse::NoDecisionMade) {
10540+ #if !defined(_WIN32) || \
10541+ defined (CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)
1053210542 verify_result_ = SSL_get_verify_result (ssl2);
1053310543
1053410544 if (verify_result_ != X509_V_OK) {
1053510545 last_openssl_error_ = static_cast <unsigned long >(verify_result_);
1053610546 error = Error::SSLServerVerification;
1053710547 return false ;
1053810548 }
10549+ #endif // not _WIN32 ||
10550+ // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
1053910551
1054010552 auto server_cert = SSL_get1_peer_certificate (ssl2);
1054110553 auto se = detail::scope_exit ([&] { X509_free (server_cert); });
@@ -10546,13 +10558,96 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
1054610558 return false ;
1054710559 }
1054810560
10561+ #if !defined(_WIN32) || \
10562+ defined (CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)
1054910563 if (server_hostname_verification_) {
1055010564 if (!verify_host (server_cert)) {
1055110565 last_openssl_error_ = X509_V_ERR_HOSTNAME_MISMATCH;
1055210566 error = Error::SSLServerHostnameVerification;
1055310567 return false ;
1055410568 }
1055510569 }
10570+ #else // _WIN32 && !
10571+ // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE Convert
10572+ // OpenSSL certificate to DER format
10573+ auto der_cert =
10574+ std::vector<unsigned char >(i2d_X509 (server_cert, nullptr ));
10575+ auto der_cert_data = der_cert.data ();
10576+ if (i2d_X509 (server_cert, &der_cert_data) < 0 ) {
10577+ error = Error::SSLServerVerification;
10578+ return false ;
10579+ }
10580+
10581+ // Create a certificate context from the DER-encoded certificate
10582+ auto cert_context = CertCreateCertificateContext (
10583+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, der_cert.data (),
10584+ static_cast <DWORD>(der_cert.size ()));
10585+
10586+ if (cert_context == nullptr ) {
10587+ error = Error::SSLServerVerification;
10588+ return false ;
10589+ }
10590+
10591+ auto chain_para = CERT_CHAIN_PARA{};
10592+ chain_para.cbSize = sizeof (chain_para);
10593+ chain_para.dwUrlRetrievalTimeout = 10 * 1000 ;
10594+
10595+ auto chain_context = PCCERT_CHAIN_CONTEXT{};
10596+ auto result = CertGetCertificateChain (
10597+ nullptr , cert_context, nullptr , cert_context->hCertStore ,
10598+ &chain_para,
10599+ CERT_CHAIN_CACHE_END_CERT |
10600+ CERT_CHAIN_REVOCATION_CHECK_END_CERT |
10601+ CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT,
10602+ nullptr , &chain_context);
10603+
10604+ CertFreeCertificateContext (cert_context);
10605+
10606+ if (!result || chain_context == nullptr ) {
10607+ error = Error::SSLServerVerification;
10608+ return false ;
10609+ }
10610+
10611+ // Verify chain policy
10612+ auto extra_policy_para = SSL_EXTRA_CERT_CHAIN_POLICY_PARA{};
10613+ extra_policy_para.cbSize = sizeof (extra_policy_para);
10614+ extra_policy_para.dwAuthType = AUTHTYPE_SERVER;
10615+ auto whost = detail::u8string_to_wstring (host_.c_str ());
10616+ if (server_hostname_verification_) {
10617+ extra_policy_para.pwszServerName =
10618+ const_cast <wchar_t *>(whost.c_str ());
10619+ }
10620+
10621+ auto policy_para = CERT_CHAIN_POLICY_PARA{};
10622+ policy_para.cbSize = sizeof (policy_para);
10623+ policy_para.dwFlags =
10624+ CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS;
10625+ policy_para.pvExtraPolicyPara = &extra_policy_para;
10626+
10627+ auto policy_status = CERT_CHAIN_POLICY_STATUS{};
10628+ policy_status.cbSize = sizeof (policy_status);
10629+
10630+ result = CertVerifyCertificateChainPolicy (
10631+ CERT_CHAIN_POLICY_SSL, chain_context, &policy_para,
10632+ &policy_status);
10633+
10634+ CertFreeCertificateChain (chain_context);
10635+
10636+ if (!result) {
10637+ error = Error::SSLServerVerification;
10638+ return false ;
10639+ }
10640+
10641+ if (policy_status.dwError != 0 ) {
10642+ if (policy_status.dwError == CERT_E_CN_NO_MATCH) {
10643+ error = Error::SSLServerHostnameVerification;
10644+ } else {
10645+ error = Error::SSLServerVerification;
10646+ }
10647+ return false ;
10648+ }
10649+ #endif // not _WIN32 ||
10650+ // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
1055610651 }
1055710652 }
1055810653
0 commit comments