Skip to content

Commit 4b2f86c

Browse files
committed
Fixed ssl context callback support
1 parent e385bae commit 4b2f86c

File tree

2 files changed

+50
-138
lines changed

2 files changed

+50
-138
lines changed

cpr/callback.cpp

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <functional>
22
#ifdef OPENSSL_BACKEND_USED
33
#include <iostream>
4+
#include <sstream>
45
#endif // OPENSSL_BACKEND_USED
56

67
#include "cpr/callback.h"
@@ -9,7 +10,9 @@
910

1011
#ifdef OPENSSL_BACKEND_USED
1112
#include <openssl/bio.h>
13+
#include <openssl/err.h>
1214
#include <openssl/pem.h>
15+
#include <openssl/pemerr.h>
1316
#include <openssl/ssl.h>
1417
#include <openssl/x509.h>
1518
#include <openssl/x509_vfy.h>
@@ -38,6 +41,31 @@ bool CancellationCallback::operator()(cpr_pf_arg_t dltotal, cpr_pf_arg_t dlnow,
3841

3942
#ifdef OPENSSL_BACKEND_USED
4043
namespace ssl {
44+
template <auto fn>
45+
struct deleter_from_fn {
46+
template <typename T>
47+
constexpr void operator()(T* arg) const {
48+
fn(arg);
49+
}
50+
};
51+
52+
template <typename T, auto fn>
53+
using custom_unique_ptr = std::unique_ptr<T, deleter_from_fn<fn>>;
54+
using x509_ptr = custom_unique_ptr<X509, X509_free>;
55+
using bio_ptr = custom_unique_ptr<BIO, BIO_free>;
56+
57+
inline std::string get_openssl_print_errors() {
58+
std::ostringstream oss;
59+
ERR_print_errors_cb(
60+
[](char const* str, size_t len, void* data) -> int {
61+
auto& oss = *static_cast<std::ostringstream*>(data);
62+
oss << str;
63+
return static_cast<int>(len);
64+
},
65+
&oss);
66+
return oss.str();
67+
}
68+
4169
/**
4270
* The ssl_ctx parameter is actually a pointer to the SSL library's SSL_CTX for OpenSSL.
4371
* If an error is returned from the callback no attempt to establish a connection is made and
@@ -49,43 +77,38 @@ namespace ssl {
4977
CURLcode tryLoadCaCertFromBuffer(CURL* /*curl*/, void* sslctx, void* raw_cert_buf) {
5078
// Check arguments
5179
if (raw_cert_buf == nullptr || sslctx == nullptr) {
52-
std::cerr << "CPR SSL context invalid callback arguments!\n";
80+
std::cerr << "Invalid callback arguments!\n";
5381
return CURLE_ABORTED_BY_CALLBACK;
5482
}
5583

56-
// Setup pointer
57-
X509_STORE* store = nullptr;
58-
X509* cert = nullptr;
59-
BIO* bio = nullptr;
60-
char* cert_buf = static_cast<char*>(raw_cert_buf);
84+
// Get a pointer to the current certificate verification storage
85+
auto* store = SSL_CTX_get_cert_store(static_cast<SSL_CTX*>(sslctx));
6186

6287
// Create a memory BIO using the data of cert_buf.
6388
// Note: It is assumed, that cert_buf is nul terminated and its length is determined by strlen.
64-
bio = BIO_new_mem_buf(cert_buf, -1);
89+
const bio_ptr bio{BIO_new_mem_buf(static_cast<char*>(raw_cert_buf), -1)};
6590

66-
// Load the PEM formatted certicifate into an X509 structure which OpenSSL can use.
67-
PEM_read_bio_X509(bio, &cert, nullptr, nullptr);
68-
if (cert == nullptr) {
69-
std::cerr << "CPR SSL context PEM_read_bio_X509 failed!\n";
70-
return CURLE_ABORTED_BY_CALLBACK;
71-
}
72-
73-
// Get a pointer to the current certificate verification storage
74-
store = SSL_CTX_get_cert_store(static_cast<SSL_CTX*>(sslctx));
91+
bool at_least_got_one = false;
92+
for (;;) {
93+
// Load the PEM formatted certicifate into an X509 structure which OpenSSL can use.
94+
const x509_ptr x{PEM_read_bio_X509_AUX(bio.get(), nullptr, nullptr, nullptr)};
95+
if (x == nullptr) {
96+
if ((ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) && at_least_got_one) {
97+
ERR_clear_error();
98+
break;
99+
}
100+
std::cerr << "PEM_read_bio_X509_AUX failed: \n" << get_openssl_print_errors() << '\n';
101+
return CURLE_ABORTED_BY_CALLBACK;
102+
}
75103

76-
// Add the loaded certificate to the verification storage
77-
const int status = X509_STORE_add_cert(store, cert);
78-
if (status == 0) {
79-
std::cerr << "CPR SSL context error adding certificate!\n";
80-
return CURLE_ABORTED_BY_CALLBACK;
104+
// Add the loaded certificate to the verification storage
105+
if (X509_STORE_add_cert(store, x.get()) == 0) {
106+
std::cerr << "X509_STORE_add_cert failed: \n" << get_openssl_print_errors() << '\n';
107+
return CURLE_ABORTED_BY_CALLBACK;
108+
}
109+
at_least_got_one = true;
81110
}
82111

83-
// Decrement the reference count of the X509 structure cert and frees it up
84-
X509_free(cert);
85-
86-
// Free the entire bio chain
87-
BIO_free(bio);
88-
89112
// The CA certificate was loaded successfully into the verification storage
90113
return CURLE_OK;
91114
}

cpr/ssl_ctx.cpp

Lines changed: 0 additions & 111 deletions
This file was deleted.

0 commit comments

Comments
 (0)