From 53fa8ef8ba3a08fe601601ffd9286d438af39b93 Mon Sep 17 00:00:00 2001 From: Fabian Wosar Date: Thu, 6 Nov 2025 12:48:28 +0000 Subject: [PATCH] Implement support for CURLOPT_CAINFO_BLOB --- cpr/session.cpp | 10 ++++++++++ include/cpr/ssl_options.h | 22 ++++++++++++++++++++++ test/ssl_tests.cpp | 20 ++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/cpr/session.cpp b/cpr/session.cpp index 59e2b64e6..82cfd8ba0 100644 --- a/cpr/session.cpp +++ b/cpr/session.cpp @@ -594,6 +594,16 @@ void Session::SetSslOptions(const SslOptions& options) { if (!options.ca_info.empty()) { curl_easy_setopt(curl_->handle, CURLOPT_CAINFO, options.ca_info.c_str()); } +#if SUPPORT_CURLOPT_CAINFO_BLOB + if (!options.ca_info_blob.empty()) { + std::string cainfo_blob(options.ca_info_blob); + curl_blob blob{}; + blob.data = cainfo_blob.data(); + blob.len = cainfo_blob.length(); + blob.flags = CURL_BLOB_COPY; + curl_easy_setopt(curl_->handle, CURLOPT_CAINFO_BLOB, &blob); + } +#endif if (!options.ca_path.empty()) { curl_easy_setopt(curl_->handle, CURLOPT_CAPATH, options.ca_path.c_str()); } diff --git a/include/cpr/ssl_options.h b/include/cpr/ssl_options.h index 09d1db2f4..571d6c8ab 100644 --- a/include/cpr/ssl_options.h +++ b/include/cpr/ssl_options.h @@ -67,6 +67,9 @@ #ifndef SUPPORT_CURLOPT_SSL_CTX_FUNCTION #define SUPPORT_CURLOPT_SSL_CTX_FUNCTION LIBCURL_VERSION_NUM >= 0x070B00 // 7.11.0 #endif +#ifndef SUPPORT_CURLOPT_CAINFO_BLOB +#define SUPPORT_CURLOPT_CAINFO_BLOB LIBCURL_VERSION_NUM >= 0x074D00 // 7.77.0 +#endif namespace cpr { @@ -312,6 +315,17 @@ class CaInfo { fs::path filename; }; +#if SUPPORT_CURLOPT_CAINFO_BLOB +// Certificate Authority (CA) bundle as blob +class CaInfoBlob { +public: + // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) + CaInfoBlob(std::string&& p_blob) : blob(std::move(p_blob)) {} + + std::string blob; +}; +#endif + // specify directory holding CA certificates class CaPath { public: @@ -436,6 +450,9 @@ struct SslOptions { #endif // We don't use fs::path here, as this leads to problems using windows std::string ca_info; +#if SUPPORT_CURLOPT_CAINFO_BLOB + std::string ca_info_blob; +#endif // We don't use fs::path here, as this leads to problems using windows std::string ca_path; #if SUPPORT_CURLOPT_SSL_CTX_FUNCTION @@ -556,6 +573,11 @@ struct SslOptions { void SetOption(const ssl::CaInfo& opt) { ca_info = opt.filename.string(); } +#if SUPPORT_CURLOPT_CAINFO_BLOB + void SetOption(const ssl::CaInfoBlob& opt) { + ca_info_blob = opt.blob; + } +#endif void SetOption(const ssl::CaPath& opt) { ca_path = opt.filename.string(); } diff --git a/test/ssl_tests.cpp b/test/ssl_tests.cpp index c77f452fa..78e42faff 100644 --- a/test/ssl_tests.cpp +++ b/test/ssl_tests.cpp @@ -180,6 +180,26 @@ TEST(SslTests, LoadKeyFromBlobTestSimpel) { } #endif +#if SUPPORT_CURLOPT_CAINFO_BLOB +TEST(SslTests, CaInfoBlobTestSimpel) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + + Url url{server->GetBaseUrl() + "/hello.html"}; + std::string baseDirPath{server->getBaseDirPath()}; + std::string crtPath{baseDirPath + "certificates/"}; + std::string keyPath{baseDirPath + "keys/"}; + + SslOptions sslOpts = Ssl(ssl::CaInfoBlob{loadFileContent(crtPath + "ca-bundle.crt")}, ssl::CertFile{crtPath + "client.crt"}, ssl::KeyFile{keyPath + "client.key"}, ssl::VerifyPeer{true}, ssl::PinnedPublicKey{keyPath + "server.pub"}, ssl::VerifyHost{true}, ssl::VerifyStatus{false}); + Response response = cpr::Get(url, sslOpts, Timeout{5000}, Verbose{}); + std::string expected_text = "Hello world!"; + EXPECT_EQ(expected_text, response.text); + EXPECT_EQ(url, response.url); + EXPECT_EQ(std::string{"text/html"}, response.header["content-type"]); + EXPECT_EQ(200, response.status_code); + EXPECT_EQ(ErrorCode::OK, response.error.code) << response.error.message; +} +#endif + fs::path GetBasePath(const std::string& execPath) { return fs::path(fs::path{execPath}.parent_path().string() + "/").make_preferred(); }