Skip to content

Commit

Permalink
Fixed ssl context callback support
Browse files Browse the repository at this point in the history
  • Loading branch information
COM8 committed May 30, 2024
1 parent b0cddac commit 4a460b7
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 138 deletions.
77 changes: 50 additions & 27 deletions cpr/callback.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <functional>
#ifdef OPENSSL_BACKEND_USED
#include <iostream>
#include <sstream>
#endif // OPENSSL_BACKEND_USED

#include "cpr/callback.h"
Expand All @@ -9,7 +10,9 @@

#ifdef OPENSSL_BACKEND_USED
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/pemerr.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
Expand Down Expand Up @@ -38,6 +41,31 @@ bool CancellationCallback::operator()(cpr_pf_arg_t dltotal, cpr_pf_arg_t dlnow,

#ifdef OPENSSL_BACKEND_USED
namespace ssl {
template <auto fn>
struct deleter_from_fn {
template <typename T>
constexpr void operator()(T* arg) const {
fn(arg);
}
};

template <typename T, auto fn>
using custom_unique_ptr = std::unique_ptr<T, deleter_from_fn<fn>>;
using x509_ptr = custom_unique_ptr<X509, X509_free>;
using bio_ptr = custom_unique_ptr<BIO, BIO_free>;

inline std::string get_openssl_print_errors() {
std::ostringstream oss;
ERR_print_errors_cb(
[](char const* str, size_t len, void* data) -> int {
auto& oss = *static_cast<std::ostringstream*>(data);
oss << str;
return static_cast<int>(len);
},
&oss);
return oss.str();
}

/**
* The ssl_ctx parameter is actually a pointer to the SSL library's SSL_CTX for OpenSSL.
* If an error is returned from the callback no attempt to establish a connection is made and
Expand All @@ -49,43 +77,38 @@ namespace ssl {
CURLcode tryLoadCaCertFromBuffer(CURL* /*curl*/, void* sslctx, void* raw_cert_buf) {
// Check arguments
if (raw_cert_buf == nullptr || sslctx == nullptr) {
std::cerr << "CPR SSL context invalid callback arguments!\n";
std::cerr << "Invalid callback arguments!\n";
return CURLE_ABORTED_BY_CALLBACK;
}

// Setup pointer
X509_STORE* store = nullptr;
X509* cert = nullptr;
BIO* bio = nullptr;
char* cert_buf = static_cast<char*>(raw_cert_buf);
// Get a pointer to the current certificate verification storage
auto* store = SSL_CTX_get_cert_store(static_cast<SSL_CTX*>(sslctx));

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

// Load the PEM formatted certicifate into an X509 structure which OpenSSL can use.
PEM_read_bio_X509(bio, &cert, nullptr, nullptr);
if (cert == nullptr) {
std::cerr << "CPR SSL context PEM_read_bio_X509 failed!\n";
return CURLE_ABORTED_BY_CALLBACK;
}

// Get a pointer to the current certificate verification storage
store = SSL_CTX_get_cert_store(static_cast<SSL_CTX*>(sslctx));
bool at_least_got_one = false;
for (;;) {
// Load the PEM formatted certicifate into an X509 structure which OpenSSL can use.
const x509_ptr x{PEM_read_bio_X509_AUX(bio.get(), nullptr, nullptr, nullptr)};
if (x == nullptr) {
if ((ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) && at_least_got_one) {
ERR_clear_error();
break;
}
std::cerr << "PEM_read_bio_X509_AUX failed: \n" << get_openssl_print_errors() << '\n';
return CURLE_ABORTED_BY_CALLBACK;
}

// Add the loaded certificate to the verification storage
const int status = X509_STORE_add_cert(store, cert);
if (status == 0) {
std::cerr << "CPR SSL context error adding certificate!\n";
return CURLE_ABORTED_BY_CALLBACK;
// Add the loaded certificate to the verification storage
if (X509_STORE_add_cert(store, x.get()) == 0) {
std::cerr << "X509_STORE_add_cert failed: \n" << get_openssl_print_errors() << '\n';
return CURLE_ABORTED_BY_CALLBACK;
}
at_least_got_one = true;
}

// Decrement the reference count of the X509 structure cert and frees it up
X509_free(cert);

// Free the entire bio chain
BIO_free(bio);

// The CA certificate was loaded successfully into the verification storage
return CURLE_OK;
}
Expand Down
111 changes: 0 additions & 111 deletions cpr/ssl_ctx.cpp

This file was deleted.

0 comments on commit 4a460b7

Please sign in to comment.