diff --git a/olp-cpp-sdk-core/include/olp/core/http/NetworkProxySettings.h b/olp-cpp-sdk-core/include/olp/core/http/NetworkProxySettings.h index ee2ba6f17..5c32915a5 100644 --- a/olp-cpp-sdk-core/include/olp/core/http/NetworkProxySettings.h +++ b/olp-cpp-sdk-core/include/olp/core/http/NetworkProxySettings.h @@ -35,12 +35,12 @@ class CORE_API NetworkProxySettings final { public: /// The proxy type. enum class Type { - NONE, ///< Don't use the proxy. - HTTP, ///< HTTP proxy as in https://www.ietf.org/rfc/rfc2068.txt - HTTPS, ///< HTTPS proxy as in https://www.ietf.org/rfc/rfc2818.txt - SOCKS4, ///< SOCKS4 proxy. - SOCKS4A, ///< SOCKS4a proxy. Proxy resolves the URL hostname. - SOCKS5, ///< SOCKS5 proxy. + NONE, ///< Don't use the proxy. + HTTP, ///< HTTP proxy as in https://www.ietf.org/rfc/rfc2068.txt + HTTPS, ///< HTTPS proxy as in https://www.ietf.org/rfc/rfc2818.txt + SOCKS4, ///< SOCKS4 proxy. + SOCKS4A, ///< SOCKS4a proxy. Proxy resolves the URL hostname. + SOCKS5, ///< SOCKS5 proxy. SOCKS5_HOSTNAME, ///< SOCKS5 Proxy. Proxy resolves the URL hostname. }; @@ -124,6 +124,28 @@ class CORE_API NetworkProxySettings final { */ NetworkProxySettings& WithPassword(std::string password); + /** + * @brief Gets the HTTPS proxy CA certificate blob. + * + * @return The PEM-encoded CA certificates used to verify the TLS + * certificate presented by an HTTPS proxy. + */ + const std::string& GetCaInfoBlob() const; + + /** + * @brief Sets the HTTPS proxy CA certificate blob. + * + * The blob contains PEM-encoded CA certificates used only to verify the TLS + * certificate presented by an HTTPS proxy. It corresponds to libcurl + * `CURLOPT_PROXY_CAINFO_BLOB` and is distinct from origin-server certificate + * settings. + * + * @param[in] ca_info_blob The PEM-encoded HTTPS proxy CA certificates. + * + * @return A reference to *this. + */ + NetworkProxySettings& WithCaInfoBlob(std::string ca_info_blob); + private: /// The proxy type. Type type_{Type::NONE}; @@ -135,6 +157,8 @@ class CORE_API NetworkProxySettings final { std::string username_; /// The proxy password. std::string password_; + /// The PEM-encoded HTTPS proxy CA certificates. + std::string ca_info_blob_; }; } // namespace http diff --git a/olp-cpp-sdk-core/src/http/NetworkProxySettings.cpp b/olp-cpp-sdk-core/src/http/NetworkProxySettings.cpp index e98cd54ca..cabfd5f1d 100644 --- a/olp-cpp-sdk-core/src/http/NetworkProxySettings.cpp +++ b/olp-cpp-sdk-core/src/http/NetworkProxySettings.cpp @@ -40,6 +40,10 @@ const std::string& NetworkProxySettings::GetPassword() const { return password_; } +const std::string& NetworkProxySettings::GetCaInfoBlob() const { + return ca_info_blob_; +} + NetworkProxySettings& NetworkProxySettings::WithHostname(std::string hostname) { hostname_ = std::move(hostname); return *this; @@ -65,5 +69,11 @@ NetworkProxySettings& NetworkProxySettings::WithPassword(std::string password) { return *this; } +NetworkProxySettings& NetworkProxySettings::WithCaInfoBlob( + std::string ca_info_blob) { + ca_info_blob_ = std::move(ca_info_blob); + return *this; +} + } // namespace http } // namespace olp diff --git a/olp-cpp-sdk-core/src/http/curl/NetworkCurl.cpp b/olp-cpp-sdk-core/src/http/curl/NetworkCurl.cpp index 8251c0896..a9ab87800 100644 --- a/olp-cpp-sdk-core/src/http/curl/NetworkCurl.cpp +++ b/olp-cpp-sdk-core/src/http/curl/NetworkCurl.cpp @@ -337,6 +337,15 @@ void SetupProxy(CURL* curl_handle, const NetworkProxySettings& proxy) { curl_easy_setopt(curl_handle, CURLOPT_PROXYUSERNAME, username.c_str()); curl_easy_setopt(curl_handle, CURLOPT_PROXYPASSWORD, password.c_str()); } + +#ifdef OLP_SDK_CURL_HAS_SUPPORT_SSL_BLOBS + const auto& ca_info_blob = proxy.GetCaInfoBlob(); + curl_blob proxy_ca_info_blob{}; + proxy_ca_info_blob.data = const_cast(ca_info_blob.data()); + proxy_ca_info_blob.len = ca_info_blob.size(); + proxy_ca_info_blob.flags = CURL_BLOB_COPY; + curl_easy_setopt(curl_handle, CURLOPT_PROXY_CAINFO_BLOB, &proxy_ca_info_blob); +#endif } void SetupRequestBody(CURL* curl_handle, diff --git a/olp-cpp-sdk-core/tests/client/OlpClientTest.cpp b/olp-cpp-sdk-core/tests/client/OlpClientTest.cpp index 1d9a296d0..3b4c7cae7 100644 --- a/olp-cpp-sdk-core/tests/client/OlpClientTest.cpp +++ b/olp-cpp-sdk-core/tests/client/OlpClientTest.cpp @@ -584,13 +584,16 @@ TEST_P(OlpClientTest, Timeout) { TEST_P(OlpClientTest, Proxy) { auto network = network_; client_settings_.retry_settings.timeout = 100; + const auto expected_ca_info_blob = + "-----BEGIN CERTIFICATE-----\nproxy-ca\n-----END CERTIFICATE-----\n"; auto expected_settings = olp::http::NetworkProxySettings() .WithHostname("somewhere") .WithPort(1080) - .WithType(olp::http::NetworkProxySettings::Type::HTTP) + .WithType(olp::http::NetworkProxySettings::Type::HTTPS) .WithUsername("username1") - .WithPassword("1"); + .WithPassword("1") + .WithCaInfoBlob(expected_ca_info_blob); client_settings_.proxy_settings = expected_settings; olp::http::NetworkProxySettings result_settings; @@ -628,7 +631,8 @@ TEST_P(OlpClientTest, Proxy) { ASSERT_EQ(expected_settings.GetPassword(), result_settings.GetPassword()); ASSERT_EQ(expected_settings.GetPort(), result_settings.GetPort()); ASSERT_EQ(expected_settings.GetUsername(), result_settings.GetUsername()); - ASSERT_EQ(expected_settings.GetPassword(), result_settings.GetPassword()); + ASSERT_EQ(expected_settings.GetType(), result_settings.GetType()); + ASSERT_EQ(expected_ca_info_blob, result_settings.GetCaInfoBlob()); testing::Mock::VerifyAndClearExpectations(network.get()); }