diff --git a/autotest/client_autotest.cc b/autotest/client_autotest.cc index b884036..cc34ba4 100644 --- a/autotest/client_autotest.cc +++ b/autotest/client_autotest.cc @@ -8,16 +8,6 @@ // ----------------------------------------------------------------------------- -#if (defined(_WIN32) || defined(_WIN64)) -// You need to set environment variable SSL_CERT_FILE properly to enable -// SSL verification. -bool kSslVerify = false; -#else -bool kSslVerify = true; -#endif - -// ----------------------------------------------------------------------------- - // JSON helper functions (based on jsoncpp). // Parse a string to JSON object. @@ -97,8 +87,6 @@ TEST(ClientTest, Get_Shortcut) { TEST(ClientTest, Get_SSL) { webcc::ClientSession session; - session.set_ssl_verify(kSslVerify); - try { // HTTPS is auto-detected from the URL scheme. auto r = session.Request(webcc::RequestBuilder{}.Get(). diff --git a/examples/client_basics.cc b/examples/client_basics.cc index 79beae4..192c74d 100644 --- a/examples/client_basics.cc +++ b/examples/client_basics.cc @@ -3,14 +3,6 @@ #include "webcc/client_session.h" #include "webcc/logger.h" -#if (defined(_WIN32) || defined(_WIN64)) -// You need to set environment variable SSL_CERT_FILE properly to enable -// SSL verification. -bool kSslVerify = false; -#else -bool kSslVerify = true; -#endif - static void PrintSeparator() { static const std::string s_line(80, '-'); std::cout << s_line << std::endl; @@ -21,8 +13,6 @@ int main() { webcc::ClientSession session; - session.set_ssl_verify(kSslVerify); - try { PrintSeparator(); diff --git a/examples/file_upload_client.cc b/examples/file_upload_client.cc index 5cb37f8..8c67be9 100644 --- a/examples/file_upload_client.cc +++ b/examples/file_upload_client.cc @@ -5,14 +5,6 @@ #include "webcc/client_session.h" #include "webcc/logger.h" -#if (defined(_WIN32) || defined(_WIN64)) -// You need to set environment variable SSL_CERT_FILE properly to enable -// SSL verification. -bool kSslVerify = false; -#else -bool kSslVerify = true; -#endif - void Help(const char* argv0) { std::cout << "Usage: " << argv0 << " [url]" << std::endl; std::cout << "Default Url: http://httpbin.org/post" << std::endl; diff --git a/examples/github_client.cc b/examples/github_client.cc index 44d648f..e6954e0 100644 --- a/examples/github_client.cc +++ b/examples/github_client.cc @@ -10,14 +10,6 @@ // Change to 1 to print response JSON. #define PRINT_RESPONSE 0 -#if (defined(_WIN32) || defined(_WIN64)) -// You need to set environment variable SSL_CERT_FILE properly to enable -// SSL verification. -bool kSslVerify = false; -#else -bool kSslVerify = true; -#endif - const std::string kUrlRoot = "https://api.github.com"; // ----------------------------------------------------------------------------- @@ -136,8 +128,6 @@ int main() { webcc::ClientSession session; - session.set_ssl_verify(kSslVerify); - ListEvents(session); return 0; diff --git a/webcc/socket.cc b/webcc/socket.cc index 6ae3b84..ffca6a6 100644 --- a/webcc/socket.cc +++ b/webcc/socket.cc @@ -1,5 +1,17 @@ #include "webcc/socket.h" +#if WEBCC_ENABLE_SSL +#if (defined(_WIN32) || defined(_WIN64)) + +#include +#include +#include + +#include "openssl/x509.h" + +#endif // defined(_WIN32) || defined(_WIN64) +#endif // WEBCC_ENABLE_SSL + #include "boost/asio/connect.hpp" #include "boost/asio/read.hpp" #include "boost/asio/write.hpp" @@ -38,14 +50,56 @@ void Socket::Close(boost::system::error_code* ec) { #if WEBCC_ENABLE_SSL +#if (defined(_WIN32) || defined(_WIN64)) + +// See: https://stackoverflow.com/a/40046425/6825348 +static bool UseSystemCertificateStore(SSL_CTX* ssl_ctx) { + // NOTE: Cannot use nullptr to replace NULL. + HCERTSTORE cert_store = ::CertOpenSystemStoreW(NULL, L"ROOT"); + + if (cert_store == nullptr) { + LOG_ERRO("Cannot open Windows system certificate store."); + return false; + } + + X509_STORE* x509_store = SSL_CTX_get_cert_store(ssl_ctx); + PCCERT_CONTEXT cert_context = nullptr; + + while (cert_context = CertEnumCertificatesInStore(cert_store, cert_context)) { + auto in = (const unsigned char **)&cert_context->pbCertEncoded; + X509* x509 = d2i_X509(nullptr, in, cert_context->cbCertEncoded); + + if (x509 != nullptr) { + if (X509_STORE_add_cert(x509_store, x509) == 0) { + LOG_ERRO("Cannot add Windows root certificate."); + } + + X509_free(x509); + } + } + + CertFreeCertificateContext(cert_context); + CertCloseStore(cert_store, 0); + + return true; +} + +#endif // defined(_WIN32) || defined(_WIN64) + namespace ssl = boost::asio::ssl; SslSocket::SslSocket(boost::asio::io_context& io_context, bool ssl_verify) : ssl_context_(ssl::context::sslv23), ssl_socket_(io_context, ssl_context_), ssl_verify_(ssl_verify) { +#if (defined(_WIN32) || defined(_WIN64)) + if (ssl_verify_) { + UseSystemCertificateStore(ssl_context_.native_handle()); + } +#else // Use the default paths for finding CA certificates. ssl_context_.set_default_verify_paths(); +#endif // defined(_WIN32) || defined(_WIN64) } void SslSocket::Connect(const std::string& host, const Endpoints& endpoints,