From 46212e2c46aefb45ba2e1d1305fa48b48dadf36b Mon Sep 17 00:00:00 2001 From: arekmula Date: Sat, 27 Jan 2024 23:00:44 +0100 Subject: [PATCH 1/5] Intitial implementation of ssl ctx callback --- cpr/session.cpp | 7 +++++++ cpr/util.cpp | 8 ++++++++ include/cpr/callback.h | 19 +++++++++++++++++++ include/cpr/session.h | 3 +++ include/cpr/util.h | 1 + 5 files changed, 38 insertions(+) diff --git a/cpr/session.cpp b/cpr/session.cpp index 97eb93a71..f07473b7b 100644 --- a/cpr/session.cpp +++ b/cpr/session.cpp @@ -319,6 +319,12 @@ void Session::SetDebugCallback(const DebugCallback& debug) { curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, 1L); } +void Session::SetCertificateCallback(const CertificateCallback& certificate) { + curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_FUNCTION, cpr::util::certificateUserFunction); + cbs_->certificatecb_ = certificate; + curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_DATA, &cbs_->certificatecb_); +} + void Session::SetUrl(const Url& url) { url_ = url; } @@ -963,6 +969,7 @@ 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); } +void Session::SetOption(const CertificateCallback& certificate){ SetCertificateCallback(certificate); } 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..9cb366083 100644 --- a/cpr/util.cpp +++ b/cpr/util.cpp @@ -161,6 +161,14 @@ int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t s return 0; } +int certificateUserFunction(CURL* /*handle*/, void* ssl_ctx, const CertificateCallback* callback) { + bool res = (*callback)(ssl_ctx); + + // Note: The CertificateCallback returns true if everything succeded and false otherwise. + // However in CURL 0 indicates success + return res; +} + /** * 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..217795b86 100644 --- a/include/cpr/callback.h +++ b/include/cpr/callback.h @@ -105,6 +105,25 @@ class CancellationCallback { std::optional> user_cb; }; +/** + * Functor class for certificate functions that will be used just before the initialization of an SSL connection. + */ +class CertificateCallback { + public: + CertificateCallback() = default; + explicit CertificateCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} + + /** + * Returns true if the validation succeeded. Returns false otherwise. + */ + bool 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..887431afc 100644 --- a/include/cpr/session.h +++ b/include/cpr/session.h @@ -96,6 +96,7 @@ class Session : public std::enable_shared_from_this { void SetWriteCallback(const WriteCallback& write); void SetProgressCallback(const ProgressCallback& progress); void SetDebugCallback(const DebugCallback& debug); + void SetCertificateCallback(const CertificateCallback& certificate); void SetVerbose(const Verbose& verbose); void SetInterface(const Interface& iface); void SetLocalPort(const LocalPort& local_port); @@ -145,6 +146,7 @@ class Session : public std::enable_shared_from_this { void SetOption(const WriteCallback& write); void SetOption(const ProgressCallback& progress); void SetOption(const DebugCallback& debug); + void SetOption(const CertificateCallback& certificate); void SetOption(const LowSpeed& low_speed); void SetOption(const VerifySsl& verify); void SetOption(const Verbose& verbose); @@ -254,6 +256,7 @@ class Session : public std::enable_shared_from_this { ProgressCallback progresscb_; DebugCallback debugcb_; CancellationCallback cancellationcb_; + CertificateCallback certificatecb_; }; std::unique_ptr cbs_{std::make_unique()}; diff --git a/include/cpr/util.h b/include/cpr/util.h index e619109dc..b36f964da 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); +int certificateUserFunction(CURL* handle, void* ssl_ctx, const CertificateCallback* 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); From 1f9862caf2c7629788f8844df8228e6b92c7054b Mon Sep 17 00:00:00 2001 From: arekmula Date: Sat, 27 Jan 2024 23:11:02 +0100 Subject: [PATCH 2/5] Adapt to proposed API --- cpr/session.cpp | 10 +++++----- cpr/util.cpp | 6 +++--- include/cpr/callback.h | 8 ++++---- include/cpr/session.h | 6 +++--- include/cpr/util.h | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/cpr/session.cpp b/cpr/session.cpp index f07473b7b..7c4b8a3eb 100644 --- a/cpr/session.cpp +++ b/cpr/session.cpp @@ -319,10 +319,10 @@ void Session::SetDebugCallback(const DebugCallback& debug) { curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, 1L); } -void Session::SetCertificateCallback(const CertificateCallback& certificate) { - curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_FUNCTION, cpr::util::certificateUserFunction); - cbs_->certificatecb_ = certificate; - curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_DATA, &cbs_->certificatecb_); +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_); } void Session::SetUrl(const Url& url) { @@ -969,7 +969,7 @@ 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); } -void Session::SetOption(const CertificateCallback& certificate){ SetCertificateCallback(certificate); } +void Session::SetOption(const SslCtxCallback& ssl_ctx){ SetSslCtxCallback(ssl_ctx); } 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 9cb366083..1d367fc9f 100644 --- a/cpr/util.cpp +++ b/cpr/util.cpp @@ -161,12 +161,12 @@ int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t s return 0; } -int certificateUserFunction(CURL* /*handle*/, void* ssl_ctx, const CertificateCallback* callback) { +int sslCtxUserFunction(CURL* /*handle*/, void* ssl_ctx, const SslCtxCallback* callback) { bool res = (*callback)(ssl_ctx); - // Note: The CertificateCallback returns true if everything succeded and false otherwise. + // Note: The SslCtxCallback returns true if everything succeded and false otherwise. // However in CURL 0 indicates success - return res; + return res ? 0 : 1; } /** diff --git a/include/cpr/callback.h b/include/cpr/callback.h index 217795b86..82307e172 100644 --- a/include/cpr/callback.h +++ b/include/cpr/callback.h @@ -108,13 +108,13 @@ class CancellationCallback { /** * Functor class for certificate functions that will be used just before the initialization of an SSL connection. */ -class CertificateCallback { +class SslCtxCallback { public: - CertificateCallback() = default; - explicit CertificateCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} + SslCtxCallback() = default; + explicit SslCtxCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} /** - * Returns true if the validation succeeded. Returns false otherwise. + * Returns true if callback succeeded. Returns false otherwise. */ bool operator()(void* ssl_ctx) const { return callback(ssl_ctx, userdata); diff --git a/include/cpr/session.h b/include/cpr/session.h index 887431afc..4d8b49356 100644 --- a/include/cpr/session.h +++ b/include/cpr/session.h @@ -96,7 +96,7 @@ class Session : public std::enable_shared_from_this { void SetWriteCallback(const WriteCallback& write); void SetProgressCallback(const ProgressCallback& progress); void SetDebugCallback(const DebugCallback& debug); - void SetCertificateCallback(const CertificateCallback& certificate); + void SetSslCtxCallback(const SslCtxCallback& ssl_ctx); void SetVerbose(const Verbose& verbose); void SetInterface(const Interface& iface); void SetLocalPort(const LocalPort& local_port); @@ -146,7 +146,7 @@ class Session : public std::enable_shared_from_this { void SetOption(const WriteCallback& write); void SetOption(const ProgressCallback& progress); void SetOption(const DebugCallback& debug); - void SetOption(const CertificateCallback& certificate); + void SetOption(const SslCtxCallback& ssl_ctx); void SetOption(const LowSpeed& low_speed); void SetOption(const VerifySsl& verify); void SetOption(const Verbose& verbose); @@ -256,7 +256,7 @@ class Session : public std::enable_shared_from_this { ProgressCallback progresscb_; DebugCallback debugcb_; CancellationCallback cancellationcb_; - CertificateCallback certificatecb_; + SslCtxCallback ssl_ctxcb_; }; std::unique_ptr cbs_{std::make_unique()}; diff --git a/include/cpr/util.h b/include/cpr/util.h index b36f964da..8293a008b 100644 --- a/include/cpr/util.h +++ b/include/cpr/util.h @@ -29,7 +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); -int certificateUserFunction(CURL* handle, void* ssl_ctx, const CertificateCallback* callback); +int 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); From 247eecfb22c37f57bff132d43b184f9fb9124cd6 Mon Sep 17 00:00:00 2001 From: arekmula Date: Sat, 27 Jan 2024 23:42:38 +0100 Subject: [PATCH 3/5] Added compile time flag that enables ssl ctx callback based on SSL library --- CMakeLists.txt | 6 ++++++ cpr/session.cpp | 4 ++++ include/cpr/session.h | 4 ++++ 3 files changed, 14 insertions(+) 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 7c4b8a3eb..011671be7 100644 --- a/cpr/session.cpp +++ b/cpr/session.cpp @@ -319,11 +319,13 @@ 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; @@ -969,7 +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/include/cpr/session.h b/include/cpr/session.h index 4d8b49356..67723eec4 100644 --- a/include/cpr/session.h +++ b/include/cpr/session.h @@ -96,7 +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); @@ -146,7 +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); From 5cbd68a19fb3bb8c65588a722162887bfc3a732c Mon Sep 17 00:00:00 2001 From: arekmula Date: Sun, 28 Jan 2024 00:04:24 +0100 Subject: [PATCH 4/5] Callback now returns the CURLcode instead of bool --- cpr/util.cpp | 8 ++------ include/cpr/callback.h | 9 +++------ include/cpr/util.h | 2 +- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/cpr/util.cpp b/cpr/util.cpp index 1d367fc9f..fb84b37a2 100644 --- a/cpr/util.cpp +++ b/cpr/util.cpp @@ -161,12 +161,8 @@ int debugUserFunction(CURL* /*handle*/, curl_infotype type, char* data, size_t s return 0; } -int sslCtxUserFunction(CURL* /*handle*/, void* ssl_ctx, const SslCtxCallback* callback) { - bool res = (*callback)(ssl_ctx); - - // Note: The SslCtxCallback returns true if everything succeded and false otherwise. - // However in CURL 0 indicates success - return res ? 0 : 1; +CURLcode sslCtxUserFunction(CURL* /*handle*/, void* ssl_ctx, const SslCtxCallback* callback) { + return (*callback)(ssl_ctx); } /** diff --git a/include/cpr/callback.h b/include/cpr/callback.h index 82307e172..fa413d96b 100644 --- a/include/cpr/callback.h +++ b/include/cpr/callback.h @@ -111,18 +111,15 @@ class CancellationCallback { class SslCtxCallback { public: SslCtxCallback() = default; - explicit SslCtxCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} + explicit SslCtxCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} - /** - * Returns true if callback succeeded. Returns false otherwise. - */ - bool operator()(void* ssl_ctx) const { + CURLcode operator()(void* ssl_ctx) const { return callback(ssl_ctx, userdata); } private: intptr_t userdata{}; - std::function callback; + std::function callback; }; } // namespace cpr diff --git a/include/cpr/util.h b/include/cpr/util.h index 8293a008b..0d1a165e6 100644 --- a/include/cpr/util.h +++ b/include/cpr/util.h @@ -29,7 +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); -int sslCtxUserFunction(CURL* handle, void* ssl_ctx, const SslCtxCallback* callback); +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); From 5454d3f15966f5f8fe7d990491709dcb27001309 Mon Sep 17 00:00:00 2001 From: arekmula Date: Sun, 28 Jan 2024 00:08:55 +0100 Subject: [PATCH 5/5] Match the naming of user provided data used in the cpr codebase --- include/cpr/callback.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cpr/callback.h b/include/cpr/callback.h index fa413d96b..47287ab2a 100644 --- a/include/cpr/callback.h +++ b/include/cpr/callback.h @@ -111,7 +111,7 @@ class CancellationCallback { class SslCtxCallback { public: SslCtxCallback() = default; - explicit SslCtxCallback(std::function p_callback, intptr_t p_userdata = 0) : userdata(p_userdata), callback(std::move(p_callback)) {} + 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); @@ -119,7 +119,7 @@ class SslCtxCallback { private: intptr_t userdata{}; - std::function callback; + std::function callback; }; } // namespace cpr