Skip to content

Commit 44208cf

Browse files
bl4ck5unmrtazz
authored andcommitted
add client cert & key support
closes mrtazz#51
1 parent 74f8937 commit 44208cf

4 files changed

Lines changed: 94 additions & 6 deletions

File tree

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ typedef struct {
113113
std::string username;
114114
std::string password;
115115
} basicAuth;
116+
117+
std::string certPath;
118+
std::string certType;
119+
std::string keyPath;
116120
std::string customUserAgent;
117121
struct {
118122
// total time of the last request in seconds Total time of previous
@@ -164,6 +168,21 @@ In order to provide an easy to use API, the simple usage via the static
164168
methods implicitly calls the curl global functions and is therefore also **not
165169
thread-safe**.
166170

171+
## HTTPS User Certificate
172+
173+
Simple wrapper functions are provided to allow clients to authenticate using certificates.
174+
Under the hood these wrappers set cURL options, e.g. `CURLOPT_SSLCERT`, using `curl_easy_setopt`.
175+
Note: currently `libcurl` compiled with `gnutls` (e.g. `libcurl4-gnutls-dev` on
176+
ubuntu) is buggy in that it returns a wrong error code when these options are set to invalid values.
177+
178+
```cpp
179+
// set CURLOPT_SSLCERT
180+
conn->SetCertPath(certPath);
181+
// set CURLOPT_SSLCERTTYPE
182+
conn->SetCertType(type);
183+
// set CURLOPT_SSLKEY
184+
conn->SetKeyPath(keyPath);
185+
```
167186
168187
## Dependencies
169188
- [libcurl][]

include/restclient-cpp/connection.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ class Connection {
9999
std::string username;
100100
std::string password;
101101
} basicAuth;
102+
103+
std::string certPath;
104+
std::string certType;
105+
std::string keyPath;
102106
std::string customUserAgent;
103107
RequestInfo lastRequest;
104108
} Info;
@@ -126,6 +130,15 @@ class Connection {
126130
// certificates to be used to verify peers. See CURLOPT_CAINFO
127131
void SetCAInfoFilePath(const std::string& caInfoFilePath);
128132

133+
// set CURLOPT_SSLCERT
134+
void SetCertPath(const std::string& cert);
135+
136+
// set CURLOPT_SSLCERTTYPE
137+
void SetCertType(const std::string& type);
138+
139+
// set CURLOPT_SSLKEY. Default format is PEM
140+
void SetKeyPath(const std::string& keyPath);
141+
129142
std::string GetUserAgent();
130143

131144
RestClient::Connection::Info GetInfo();
@@ -163,6 +176,9 @@ class Connection {
163176
std::string customUserAgent;
164177
std::string caInfoFilePath;
165178
RequestInfo lastRequest;
179+
std::string certPath;
180+
std::string certType;
181+
std::string keyPath;
166182
RestClient::Response performCurlRequest(const std::string& uri);
167183
};
168184
}; // namespace RestClient

source/connection.cc

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ RestClient::Connection::GetInfo() {
6060
ret.customUserAgent = this->customUserAgent;
6161
ret.lastRequest = this->lastRequest;
6262

63+
ret.certPath = this->certPath;
64+
ret.certType = this->certType;
65+
ret.keyPath = this->keyPath;
66+
6367
return ret;
6468
}
6569

@@ -175,6 +179,21 @@ RestClient::Connection::SetBasicAuth(const std::string& username,
175179
this->basicAuth.password = password;
176180
}
177181

182+
void
183+
RestClient::Connection::SetCertPath(const std::string& cert) {
184+
this->certPath = cert;
185+
}
186+
187+
void
188+
RestClient::Connection::SetCertType(const std::string& certType) {
189+
this->certType = certType;
190+
}
191+
192+
void
193+
RestClient::Connection::SetKeyPath(const std::string& keyPath) {
194+
this->keyPath = keyPath;
195+
}
196+
178197
/**
179198
* @brief helper function to get called from the actual request methods to
180199
* prepare the curlHandle for transfer with generic options, perform the
@@ -247,14 +266,38 @@ RestClient::Connection::performCurlRequest(const std::string& uri) {
247266
curl_easy_setopt(this->curlHandle, CURLOPT_CAINFO,
248267
this->caInfoFilePath.c_str());
249268
}
269+
270+
// set cert file path
271+
if (!this->certPath.empty()) {
272+
curl_easy_setopt(this->curlHandle, CURLOPT_SSLCERT,
273+
this->certPath.c_str());
274+
}
275+
276+
// set cert type
277+
if (!this->certType.empty()) {
278+
curl_easy_setopt(this->curlHandle, CURLOPT_SSLCERTTYPE,
279+
this->certType.c_str());
280+
}
281+
// set key file path
282+
if (!this->keyPath.empty()) {
283+
curl_easy_setopt(this->curlHandle, CURLOPT_SSLKEY,
284+
this->keyPath.c_str());
285+
}
286+
250287
res = curl_easy_perform(this->curlHandle);
251288
if (res != CURLE_OK) {
252-
if (res == CURLE_OPERATION_TIMEDOUT) {
253-
ret.code = res;
254-
ret.body = "Operation Timeout.";
255-
} else {
256-
ret.body = "Failed to query.";
257-
ret.code = -1;
289+
switch (res) {
290+
case CURLE_OPERATION_TIMEDOUT:
291+
ret.code = res;
292+
ret.body = "Operation Timeout.";
293+
break;
294+
case CURLE_SSL_CERTPROBLEM:
295+
ret.code = res;
296+
ret.body = curl_easy_strerror(res);
297+
break;
298+
default:
299+
ret.body = "Failed to query.";
300+
ret.code = -1;
258301
}
259302
} else {
260303
int64_t http_code = 0;

test/test_connection.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,16 @@ TEST_F(ConnectionTest, TestBasicAuth)
9292

9393
}
9494

95+
TEST_F(ConnectionTest, TestSSLCert)
96+
{
97+
conn->SetCertPath("non-existent file");
98+
conn->SetKeyPath("non-existent key path");
99+
conn->SetCertType("invalid cert type");
100+
RestClient::Response res = conn->get("/get");
101+
102+
EXPECT_EQ(58, res.code);
103+
}
104+
95105
TEST_F(ConnectionTest, TestSetHeaders)
96106
{
97107
RestClient::HeaderFields headers;

0 commit comments

Comments
 (0)