Skip to content

Commit 9063a7c

Browse files
committed
Added support for setting CURLOPT_SSLCERT_BLOB
1 parent 93c2ad6 commit 9063a7c

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

cpr/session.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,20 @@ void Session::SetSslOptions(const SslOptions& options) {
528528
curl_easy_setopt(curl_->handle, CURLOPT_SSLCERTTYPE, options.cert_type.c_str());
529529
}
530530
}
531+
#if SUPPORT_CURLOPT_SSLCERT_BLOB
532+
else if(!options.cert_blob.empty()) {
533+
std::string cert_blob(options.cert_blob);
534+
curl_blob blob{};
535+
// NOLINTNEXTLINE (readability-container-data-pointer)
536+
blob.data = &cert_blob[0];
537+
blob.len = cert_blob.length();
538+
blob.flags = CURL_BLOB_COPY;
539+
curl_easy_setopt(curl_->handle, CURLOPT_SSLCERT_BLOB, &blob);
540+
if (!options.cert_type.empty()) {
541+
curl_easy_setopt(curl_->handle, CURLOPT_SSLCERTTYPE, options.cert_type.c_str());
542+
}
543+
}
544+
#endif
531545
if (!options.key_file.empty()) {
532546
curl_easy_setopt(curl_->handle, CURLOPT_SSLKEY, options.key_file.c_str());
533547
if (!options.key_type.empty()) {

include/cpr/ssl_options.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@
7070
#ifndef SUPPORT_CURLOPT_CAINFO_BLOB
7171
#define SUPPORT_CURLOPT_CAINFO_BLOB LIBCURL_VERSION_NUM >= 0x074D00 // 7.77.0
7272
#endif
73+
#ifndef SUPPORT_CURLOPT_SSLCERT_BLOB
74+
#define SUPPORT_CURLOPT_SSLCERT_BLOB LIBCURL_VERSION_NUM >= 0x074700 // 7.71.0
75+
#endif
7376

7477
namespace cpr {
7578

@@ -117,6 +120,38 @@ class DerCert : public CertFile {
117120
}
118121
};
119122

123+
124+
#if SUPPORT_CURLOPT_SSLCERT_BLOB
125+
class CertBlob {
126+
public:
127+
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
128+
CertBlob(std::string&& p_blob) : blob(std::move(p_blob)) {}
129+
130+
virtual ~CertBlob() = default;
131+
132+
std::string blob;
133+
134+
virtual const char* GetCertType() const {
135+
return "PEM";
136+
}
137+
};
138+
139+
using PemBlob = CertBlob;
140+
141+
class DerBlob : public CertBlob {
142+
public:
143+
template <typename BlobType>
144+
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
145+
DerBlob(BlobType&& p_blob) : CertBlob(std::move(p_blob)) {}
146+
147+
~DerBlob() override = default;
148+
149+
const char* GetCertType() const override {
150+
return "DER";
151+
}
152+
};
153+
#endif
154+
120155
// specify private keyfile for TLS and SSL client cert
121156
class KeyFile {
122157
public:
@@ -423,6 +458,9 @@ class NoRevoke {
423458
struct SslOptions {
424459
// We don't use fs::path here, as this leads to problems using windows
425460
std::string cert_file;
461+
#if SUPPORT_CURLOPT_SSLCERT_BLOB
462+
util::SecureString cert_blob;
463+
#endif
426464
std::string cert_type;
427465
// We don't use fs::path here, as this leads to problems using windows
428466
std::string key_file;
@@ -472,6 +510,12 @@ struct SslOptions {
472510
cert_file = opt.filename.string();
473511
cert_type = opt.GetCertType();
474512
}
513+
#if SUPPORT_CURLOPT_SSLCERT_BLOB
514+
void SetOption(const ssl::CertBlob& opt) {
515+
cert_blob = opt.blob;
516+
cert_type = opt.GetCertType();
517+
}
518+
#endif
475519
void SetOption(const ssl::KeyFile& opt) {
476520
key_file = opt.filename.string();
477521
key_type = opt.GetKeyType();

test/ssl_tests.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,27 @@ TEST(SslTests, LoadCertFromBufferTestSimpel) {
159159
}
160160
#endif
161161

162+
#if SUPPORT_CURLOPT_SSLCERT_BLOB
163+
TEST(SslTests, LoadCertFromBlobTestSimpel) {
164+
std::this_thread::sleep_for(std::chrono::seconds(1));
165+
166+
Url url{server->GetBaseUrl() + "/hello.html"};
167+
168+
std::string baseDirPath{server->getBaseDirPath()};
169+
std::string crtPath{baseDirPath + "certificates/"};
170+
std::string keyPath{baseDirPath + "keys/"};
171+
std::string crtBuffer = loadFileContent(crtPath + "client.crt");
172+
SslOptions sslOpts = Ssl(ssl::CaInfo{crtPath + "ca-bundle.crt"}, ssl::CertBlob{std::move(crtBuffer)}, ssl::KeyFile{keyPath + "client.key"}, ssl::VerifyPeer{true}, ssl::VerifyHost{true}, ssl::VerifyStatus{false});
173+
Response response = cpr::Get(url, sslOpts, Timeout{5000}, Verbose{});
174+
std::string expected_text = "Hello world!";
175+
EXPECT_EQ(expected_text, response.text);
176+
EXPECT_EQ(url, response.url);
177+
EXPECT_EQ(std::string{"text/html"}, response.header["content-type"]);
178+
EXPECT_EQ(200, response.status_code);
179+
EXPECT_EQ(ErrorCode::OK, response.error.code) << response.error.message;
180+
}
181+
#endif
182+
162183
#if SUPPORT_CURLOPT_SSLKEY_BLOB
163184
TEST(SslTests, LoadKeyFromBlobTestSimpel) {
164185
std::this_thread::sleep_for(std::chrono::seconds(1));

0 commit comments

Comments
 (0)