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