mirror of
https://github.com/yhirose/cpp-httplib
synced 2024-11-21 06:26:02 -07:00
parent
887def9490
commit
c4f3f9529b
2 changed files with 91 additions and 21 deletions
90
httplib.h
90
httplib.h
|
@ -152,6 +152,8 @@ using ssize_t = int;
|
|||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#pragma comment(lib, "crypt32.lib")
|
||||
#pragma comment(lib, "cryptui.lib")
|
||||
#endif
|
||||
|
||||
#ifndef strcasecmp
|
||||
|
@ -1062,6 +1064,8 @@ private:
|
|||
bool connect_with_proxy(Socket &sock, Response &res, bool &success);
|
||||
bool initialize_ssl(Socket &socket);
|
||||
|
||||
bool load_certs();
|
||||
|
||||
bool verify_host(X509 *server_cert) const;
|
||||
bool verify_host_with_subject_alt_name(X509 *server_cert) const;
|
||||
bool verify_host_with_common_name(X509 *server_cert) const;
|
||||
|
@ -1069,12 +1073,14 @@ private:
|
|||
|
||||
SSL_CTX *ctx_;
|
||||
std::mutex ctx_mutex_;
|
||||
std::once_flag initialize_cert_;
|
||||
|
||||
std::vector<std::string> host_components_;
|
||||
|
||||
std::string ca_cert_file_path_;
|
||||
std::string ca_cert_dir_path_;
|
||||
X509_STORE *ca_cert_store_ = nullptr;
|
||||
bool server_certificate_verification_ = false;
|
||||
bool server_certificate_verification_ = true;
|
||||
long verify_result_ = 0;
|
||||
|
||||
friend class Client;
|
||||
|
@ -1313,9 +1319,7 @@ public:
|
|||
|
||||
void stop() { cli_->stop(); }
|
||||
|
||||
void set_tcp_nodelay(bool on) {
|
||||
cli_->set_tcp_nodelay(on);
|
||||
}
|
||||
void set_tcp_nodelay(bool on) { cli_->set_tcp_nodelay(on); }
|
||||
|
||||
void set_socket_options(SocketOptions socket_options) {
|
||||
cli_->set_socket_options(socket_options);
|
||||
|
@ -2776,7 +2780,7 @@ inline std::string params_to_query_str(const Params ¶ms) {
|
|||
if (it != params.begin()) { query += "&"; }
|
||||
query += it->first;
|
||||
query += "=";
|
||||
query += detail::encode_url(it->second);
|
||||
query += encode_url(it->second);
|
||||
}
|
||||
|
||||
return query;
|
||||
|
@ -3223,6 +3227,33 @@ inline std::string SHA_512(const std::string &s) {
|
|||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
// NOTE: This code came up with the following stackoverflow post:
|
||||
// https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
|
||||
inline bool load_system_certs_on_windows(X509_STORE *store) {
|
||||
auto hStore = CertOpenSystemStore((HCRYPTPROV_LEGACY)NULL, L"ROOT");
|
||||
|
||||
if (!hStore) { return false; }
|
||||
|
||||
PCCERT_CONTEXT pContext = NULL;
|
||||
while (pContext = CertEnumCertificatesInStore(hStore, pContext)) {
|
||||
auto encoded_cert =
|
||||
static_cast<const unsigned char *>(pContext->pbCertEncoded);
|
||||
|
||||
auto x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
|
||||
if (x509) {
|
||||
X509_STORE_add_cert(store, x509);
|
||||
X509_free(x509);
|
||||
}
|
||||
}
|
||||
|
||||
CertFreeCertificateContext(pContext);
|
||||
CertCloseStore(hStore, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
class WSInit {
|
||||
public:
|
||||
WSInit() {
|
||||
|
@ -5544,23 +5575,44 @@ inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res,
|
|||
return true;
|
||||
}
|
||||
|
||||
inline bool SSLClient::load_certs() {
|
||||
bool ret = true;
|
||||
|
||||
std::call_once(initialize_cert_, [&]() {
|
||||
std::lock_guard<std::mutex> guard(ctx_mutex_);
|
||||
if (!ca_cert_file_path_.empty()) {
|
||||
if (!SSL_CTX_load_verify_locations(ctx_, ca_cert_file_path_.c_str(),
|
||||
nullptr)) {
|
||||
ret = false;
|
||||
}
|
||||
} else if (!ca_cert_dir_path_.empty()) {
|
||||
if (!SSL_CTX_load_verify_locations(ctx_, nullptr,
|
||||
ca_cert_dir_path_.c_str())) {
|
||||
ret = false;
|
||||
}
|
||||
} else if (ca_cert_store_ != nullptr) {
|
||||
if (SSL_CTX_get_cert_store(ctx_) != ca_cert_store_) {
|
||||
SSL_CTX_set_cert_store(ctx_, ca_cert_store_);
|
||||
}
|
||||
} else {
|
||||
#ifdef _WIN32
|
||||
detail::load_system_certs_on_windows(SSL_CTX_get_cert_store(ctx_));
|
||||
#else
|
||||
SSL_CTX_set_default_verify_paths(ctx_);
|
||||
#endif
|
||||
}
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline bool SSLClient::initialize_ssl(Socket &socket) {
|
||||
auto ssl = detail::ssl_new(
|
||||
socket.sock, ctx_, ctx_mutex_,
|
||||
[&](SSL *ssl) {
|
||||
if (ca_cert_file_path_.empty() && ca_cert_store_ == nullptr) {
|
||||
SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, nullptr);
|
||||
} else if (!ca_cert_file_path_.empty()) {
|
||||
if (!SSL_CTX_load_verify_locations(ctx_, ca_cert_file_path_.c_str(),
|
||||
nullptr)) {
|
||||
return false;
|
||||
}
|
||||
SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER, nullptr);
|
||||
} else if (ca_cert_store_ != nullptr) {
|
||||
if (SSL_CTX_get_cert_store(ctx_) != ca_cert_store_) {
|
||||
SSL_CTX_set_cert_store(ctx_, ca_cert_store_);
|
||||
}
|
||||
SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER, nullptr);
|
||||
if (server_certificate_verification_) {
|
||||
if (!load_certs()) { return false; }
|
||||
SSL_set_verify(ssl, SSL_VERIFY_NONE, nullptr);
|
||||
}
|
||||
|
||||
if (SSL_connect(ssl) != 1) { return false; }
|
||||
|
@ -5750,3 +5802,5 @@ inline bool SSLClient::check_host_name(const char *pattern,
|
|||
} // namespace httplib
|
||||
|
||||
#endif // CPPHTTPLIB_HTTPLIB_H
|
||||
|
||||
|
||||
|
|
22
test/test.cc
22
test/test.cc
|
@ -765,6 +765,9 @@ protected:
|
|||
svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
|
||||
#endif
|
||||
{
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
cli_.enable_server_certificate_verification(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
|
@ -2627,6 +2630,9 @@ protected:
|
|||
svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
|
||||
#endif
|
||||
{
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
cli_.enable_server_certificate_verification(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
|
@ -2704,6 +2710,9 @@ protected:
|
|||
svr_(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE)
|
||||
#endif
|
||||
{
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
cli_.enable_server_certificate_verification(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
|
@ -2763,6 +2772,7 @@ TEST(SSLClientTest, ServerCertificateVerification1) {
|
|||
TEST(SSLClientTest, ServerCertificateVerification2) {
|
||||
SSLClient cli("google.com");
|
||||
cli.enable_server_certificate_verification(true);
|
||||
cli.set_ca_cert_path("hello");
|
||||
auto res = cli.Get("/");
|
||||
ASSERT_TRUE(res == nullptr);
|
||||
}
|
||||
|
@ -2819,8 +2829,10 @@ TEST(SSLClientServerTest, ClientCertPresent) {
|
|||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
httplib::SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||
auto res = cli.Get("/test");
|
||||
cli.enable_server_certificate_verification(false);
|
||||
cli.set_connection_timeout(30);
|
||||
|
||||
auto res = cli.Get("/test");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(200, res->status);
|
||||
|
||||
|
@ -2888,8 +2900,10 @@ TEST(SSLClientServerTest, MemoryClientCertPresent) {
|
|||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
httplib::SSLClient cli(HOST, PORT, client_cert, client_private_key);
|
||||
auto res = cli.Get("/test");
|
||||
cli.enable_server_certificate_verification(false);
|
||||
cli.set_connection_timeout(30);
|
||||
|
||||
auto res = cli.Get("/test");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(200, res->status);
|
||||
|
||||
|
@ -2934,8 +2948,10 @@ TEST(SSLClientServerTest, TrustDirOptional) {
|
|||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
httplib::SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
|
||||
auto res = cli.Get("/test");
|
||||
cli.enable_server_certificate_verification(false);
|
||||
cli.set_connection_timeout(30);
|
||||
|
||||
auto res = cli.Get("/test");
|
||||
ASSERT_TRUE(res != nullptr);
|
||||
ASSERT_EQ(200, res->status);
|
||||
|
||||
|
|
Loading…
Reference in a new issue