From 32d0e0e2543b8c9bc352aae2f55a19920d58bd88 Mon Sep 17 00:00:00 2001 From: Sergey Avseyev Date: Thu, 13 Jul 2023 19:01:57 +0300 Subject: [PATCH] CXXCBC-349: allow to pass trust certificate by value (#430) --- core/cluster.hxx | 25 +++++++++++++++++++------ core/cluster_options.hxx | 1 + core/impl/cluster.cxx | 3 +++ core/meta/features.hxx | 6 ++++++ couchbase/security_options.hxx | 16 +++++++++++++++- 5 files changed, 44 insertions(+), 7 deletions(-) diff --git a/core/cluster.hxx b/core/cluster.hxx index a73f73dff..ce7178352 100644 --- a/core/cluster.hxx +++ b/core/cluster.hxx @@ -357,6 +357,7 @@ class cluster : public std::enable_shared_from_this if (origin_.options().enable_tls /* TLS is enabled */ && origin_.options().trust_certificate.empty() /* No CA certificate (or other SDK-specific trust source) is specified */ + && origin_.options().trust_certificate_value.empty() /* and certificate value has not been specified */ && origin_.options().tls_verify != tls_verify_mode::none /* The user did not disable all TLS verification */ && has_non_capella_host /* The connection string has a hostname that does NOT end in ".cloud.couchbase.com" */) { CB_LOG_WARNING("[{}] When TLS is enabled, the cluster options must specify certificate(s) to trust or ensure that they are " @@ -386,7 +387,8 @@ class cluster : public std::enable_shared_from_this tls_.set_verify_mode(asio::ssl::verify_peer); break; } - if (origin_.options().trust_certificate.empty()) { // trust certificate is not explicitly specified + if (origin_.options().trust_certificate.empty() && + origin_.options().trust_certificate_value.empty()) { // trust certificate is not explicitly specified CB_LOG_DEBUG(R"([{}]: use default CA for TLS verify)", id_); std::error_code ec{}; @@ -422,11 +424,22 @@ class cluster : public std::enable_shared_from_this std::error_code ec{}; // load only the explicit certificate // system and default capella certificates are not loaded - CB_LOG_DEBUG(R"([{}]: use TLS verify file: "{}")", id_, origin_.options().trust_certificate); - tls_.load_verify_file(origin_.options().trust_certificate, ec); - if (ec) { - CB_LOG_ERROR("[{}]: unable to load verify file \"{}\": {}", id_, origin_.options().trust_certificate, ec.message()); - return close([ec, handler = std::forward(handler)]() mutable { return handler(ec); }); + if (!origin_.options().trust_certificate_value.empty()) { + CB_LOG_DEBUG(R"([{}]: use TLS certificate passed through via options object)", id_); + tls_.add_certificate_authority(asio::const_buffer(origin_.options().trust_certificate_value.data(), + origin_.options().trust_certificate_value.size()), + ec); + if (ec) { + CB_LOG_WARNING("[{}]: unable to load CA passed via options object: {}", id_, ec.message()); + } + } + if (!origin_.options().trust_certificate.empty()) { + CB_LOG_DEBUG(R"([{}]: use TLS verify file: "{}")", id_, origin_.options().trust_certificate); + tls_.load_verify_file(origin_.options().trust_certificate, ec); + if (ec) { + CB_LOG_ERROR("[{}]: unable to load verify file \"{}\": {}", id_, origin_.options().trust_certificate, ec.message()); + return close([ec, handler = std::forward(handler)]() mutable { return handler(ec); }); + } } } #ifdef COUCHBASE_CXX_CLIENT_TLS_KEY_LOG_FILE diff --git a/core/cluster_options.hxx b/core/cluster_options.hxx index 04cfd8672..d0496b9f5 100644 --- a/core/cluster_options.hxx +++ b/core/cluster_options.hxx @@ -53,6 +53,7 @@ struct cluster_options { bool tls_disable_deprecated_protocols{ true }; bool tls_disable_v1_2{ false }; std::string trust_certificate{}; + std::string trust_certificate_value{}; bool enable_mutation_tokens{ true }; bool enable_tcp_keep_alive{ true }; io::ip_protocol use_ip_protocol{ io::ip_protocol::any }; diff --git a/core/impl/cluster.cxx b/core/impl/cluster.cxx index 9c5ae8a23..c896a20bb 100644 --- a/core/impl/cluster.cxx +++ b/core/impl/cluster.cxx @@ -82,6 +82,9 @@ options_to_origin(const std::string& connection_string, const couchbase::cluster if (opts.security.trust_certificate.has_value()) { user_options.trust_certificate = opts.security.trust_certificate.value(); } + if (opts.security.trust_certificate_value.has_value()) { + user_options.trust_certificate_value = opts.security.trust_certificate_value.value(); + } switch (opts.security.tls_verify) { case couchbase::tls_verify_mode::none: user_options.tls_verify = core::tls_verify_mode::none; diff --git a/core/meta/features.hxx b/core/meta/features.hxx index 5cc66e33a..3b7f9c9be 100644 --- a/core/meta/features.hxx +++ b/core/meta/features.hxx @@ -29,3 +29,9 @@ * couchbase::core::meta::sdk_version() function is available */ #define COUCHBASE_CXX_CLIENT_HAS_SDK_SEMVER 1 + +/** + * couchbase::core::cluster_options and couchbase::security_options support + * passing TLS trust certificate by value + */ +#define COUCHBASE_CXX_CLIENT_CAN_PASS_TLS_TRUST_CERTIFICATE_BY_VALUE 1 diff --git a/couchbase/security_options.hxx b/couchbase/security_options.hxx index 7f9c6e714..7d4f6087f 100644 --- a/couchbase/security_options.hxx +++ b/couchbase/security_options.hxx @@ -45,10 +45,17 @@ class security_options return *this; } + auto trust_certificate_value(std::string certificate_value) -> security_options& + { + trust_certificate_value_ = certificate_value; + return *this; + } + struct built { bool enabled; tls_verify_mode tls_verify; std::optional trust_certificate; + std::optional trust_certificate_value; bool disable_mozilla_ca_certificates; bool disable_deprecated_protocols; bool disable_tls_v1_2; @@ -57,7 +64,13 @@ class security_options [[nodiscard]] auto build() const -> built { return { - enabled_, tls_verify_, trust_certificate_, disable_mozilla_ca_certificates_, disable_deprecated_protocols, disable_tls_v1_2, + enabled_, + tls_verify_, + trust_certificate_, + trust_certificate_value_, + disable_mozilla_ca_certificates_, + disable_deprecated_protocols, + disable_tls_v1_2, }; } @@ -65,6 +78,7 @@ class security_options bool enabled_{ true }; tls_verify_mode tls_verify_{ tls_verify_mode::peer }; std::optional trust_certificate_{}; + std::optional trust_certificate_value_{}; bool disable_mozilla_ca_certificates_{ false }; bool disable_deprecated_protocols{ true }; bool disable_tls_v1_2{ false };