@@ -197,6 +197,10 @@ using ssize_t = long;
197
197
#endif // NOMINMAX
198
198
199
199
#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
200
204
#include < winsock2.h>
201
205
#include < ws2tcpip.h>
202
206
@@ -6040,6 +6044,7 @@ inline bool is_ssl_peer_could_be_closed(SSL *ssl, socket_t sock) {
6040
6044
}
6041
6045
6042
6046
#ifdef _WIN32
6047
+ #ifdef CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
6043
6048
// NOTE: This code came up with the following stackoverflow post:
6044
6049
// https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
6045
6050
inline bool load_system_certs_on_windows (X509_STORE *store) {
@@ -6066,6 +6071,7 @@ inline bool load_system_certs_on_windows(X509_STORE *store) {
6066
6071
6067
6072
return result;
6068
6073
}
6074
+ #endif // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
6069
6075
#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && \
6070
6076
defined (TARGET_OS_OSX)
6071
6077
template <typename T>
@@ -10483,8 +10489,10 @@ inline bool SSLClient::load_certs() {
10483
10489
} else {
10484
10490
auto loaded = false ;
10485
10491
#ifdef _WIN32
10492
+ #ifdef CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
10486
10493
loaded =
10487
10494
detail::load_system_certs_on_windows (SSL_CTX_get_cert_store (ctx_));
10495
+ #endif // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
10488
10496
#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && \
10489
10497
defined (TARGET_OS_OSX)
10490
10498
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) {
10529
10537
}
10530
10538
10531
10539
if (verification_status == SSLVerifierResponse::NoDecisionMade) {
10540
+ #if !defined(_WIN32) || \
10541
+ defined (CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)
10532
10542
verify_result_ = SSL_get_verify_result (ssl2);
10533
10543
10534
10544
if (verify_result_ != X509_V_OK) {
10535
10545
last_openssl_error_ = static_cast <unsigned long >(verify_result_);
10536
10546
error = Error::SSLServerVerification;
10537
10547
return false ;
10538
10548
}
10549
+ #endif // not _WIN32 ||
10550
+ // CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
10539
10551
10540
10552
auto server_cert = SSL_get1_peer_certificate (ssl2);
10541
10553
auto se = detail::scope_exit ([&] { X509_free (server_cert); });
@@ -10546,13 +10558,96 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
10546
10558
return false ;
10547
10559
}
10548
10560
10561
+ #if !defined(_WIN32) || \
10562
+ defined (CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)
10549
10563
if (server_hostname_verification_) {
10550
10564
if (!verify_host (server_cert)) {
10551
10565
last_openssl_error_ = X509_V_ERR_HOSTNAME_MISMATCH;
10552
10566
error = Error::SSLServerHostnameVerification;
10553
10567
return false ;
10554
10568
}
10555
10569
}
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
10556
10651
}
10557
10652
}
10558
10653
0 commit comments