diff --git a/CMakeLists.txt b/CMakeLists.txt index 5af365768..be1e159a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,6 +170,12 @@ find_package(OpenSSL REQUIRED) add_compile_definitions(OPENSSL_BACKEND_USED) endif() +if (SSL_BACKEND_USED STREQUAL "OpenSSL" OR SSL_BACKEND_USED STREQUAL "MbedTLS") +# CURLOPT_SSL_CTX_FUNCTION works for libcurl powered by OpenSSL, wolfSSL, mbedTLS or BearSSL. +# If libcurl was built against another SSL library this functionality is absent. + add_compile_definitions(SSL_CTX_CALLBACK_ENABLED) +endif () + # Curl configuration if(CPR_USE_SYSTEM_CURL) if(CPR_ENABLE_SSL) diff --git a/cpr/session.cpp b/cpr/session.cpp index 97eb93a71..011671be7 100644 --- a/cpr/session.cpp +++ b/cpr/session.cpp @@ -319,6 +319,14 @@ void Session::SetDebugCallback(const DebugCallback& debug) { curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, 1L); } +#ifdef SSL_CTX_CALLBACK_ENABLED +void Session::SetSslCtxCallback(const SslCtxCallback& ssl_ctx) { + curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_FUNCTION, cpr::util::sslCtxUserFunction); + cbs_->ssl_ctxcb_ = ssl_ctx; + curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_DATA, &cbs_->ssl_ctxcb_); +} +#endif // SSL_CTX_CALLBACK_ENABLED + void Session::SetUrl(const Url& url) { url_ = url; } @@ -963,6 +971,9 @@ void Session::SetOption(const HeaderCallback& header) { SetHeaderCallback(header void Session::SetOption(const WriteCallback& write) { SetWriteCallback(write); } void Session::SetOption(const ProgressCallback& progress) { SetProgressCallback(progress); } void Session::SetOption(const DebugCallback& debug) { SetDebugCallback(debug); } +#ifdef SSL_CTX_CALLBACK_ENABLED +void Session::SetOption(const SslCtxCallback& ssl_ctx){ SetSslCtxCallback(ssl_ctx); } +#endif // SSL_CTX_CALLBACK_ENABLED void Session::SetOption(const Url& url) { SetUrl(url); } void Session::SetOption(const Parameters& parameters) { SetParameters(parameters); } void Session::SetOption(Parameters&& parameters) { SetParameters(std::move(parameters)); } diff --git a/cpr/util.cpp b/cpr/util.cpp index 91efa3c00..fb84b37a2 100644 --- a/cpr/util.cpp +++ b/cpr/util.cpp @@ -161,6 +161,10 @@ int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t s return 0; } +CURLcode sslCtxUserFunction(CURL* /*handle*/, void* ssl_ctx, const SslCtxCallback* callback) { + return (*callback)(ssl_ctx); +} + /** * Creates a temporary CurlHolder object and uses it to escape the given string. * If you plan to use this methode on a regular basis think about creating a CurlHolder diff --git a/include/cpr/callback.h b/include/cpr/callback.h index dc1c6eeb7..47287ab2a 100644 --- a/include/cpr/callback.h +++ b/include/cpr/callback.h @@ -105,6 +105,22 @@ class CancellationCallback { std::optional> user_cb; }; +/** + * Functor class for certificate functions that will be used just before the initialization of an SSL connection. + */ +class SslCtxCallback { + public: + SslCtxCallback() = default; + explicit SslCtxCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} + + CURLcode operator()(void* ssl_ctx) const { + return callback(ssl_ctx, userdata); + } + + private: + intptr_t userdata{}; + std::function callback; +}; } // namespace cpr diff --git a/include/cpr/session.h b/include/cpr/session.h index 0ff13f847..67723eec4 100644 --- a/include/cpr/session.h +++ b/include/cpr/session.h @@ -96,6 +96,9 @@ class Session : public std::enable_shared_from_this { void SetWriteCallback(const WriteCallback& write); void SetProgressCallback(const ProgressCallback& progress); void SetDebugCallback(const DebugCallback& debug); +#ifdef SSL_CTX_CALLBACK_ENABLED + void SetSslCtxCallback(const SslCtxCallback& ssl_ctx); +#endif // SSL_CTX_CALLBACK_ENABLED void SetVerbose(const Verbose& verbose); void SetInterface(const Interface& iface); void SetLocalPort(const LocalPort& local_port); @@ -145,6 +148,9 @@ class Session : public std::enable_shared_from_this { void SetOption(const WriteCallback& write); void SetOption(const ProgressCallback& progress); void SetOption(const DebugCallback& debug); +#ifdef SSL_CTX_CALLBACK_ENABLED + void SetOption(const SslCtxCallback& ssl_ctx); +#endif void SetOption(const LowSpeed& low_speed); void SetOption(const VerifySsl& verify); void SetOption(const Verbose& verbose); @@ -254,6 +260,7 @@ class Session : public std::enable_shared_from_this { ProgressCallback progresscb_; DebugCallback debugcb_; CancellationCallback cancellationcb_; + SslCtxCallback ssl_ctxcb_; }; std::unique_ptr cbs_{std::make_unique()}; diff --git a/include/cpr/util.h b/include/cpr/util.h index e619109dc..0d1a165e6 100644 --- a/include/cpr/util.h +++ b/include/cpr/util.h @@ -29,6 +29,7 @@ int progressUserFunction(const T* progress, cpr_pf_arg_t dltotal, cpr_pf_arg_t d return (*progress)(dltotal, dlnow, ultotal, ulnow) ? 0 : cancel_retval; } int debugUserFunction(CURL* handle, curl_infotype type, char* data, size_t size, const DebugCallback* debug); +CURLcode sslCtxUserFunction(CURL* handle, void* ssl_ctx, const SslCtxCallback* callback); std::vector split(const std::string& to_split, char delimiter); std::string urlEncode(const std::string& s); std::string urlDecode(const std::string& s);