diff options
author | Tor Brede Vekterli <vekterli@oath.com> | 2018-12-11 14:53:58 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-11 14:53:58 +0100 |
commit | a4af8e7aa38507b43fa0cb75c8af18f42203a3f3 (patch) | |
tree | eb21bc813ac7cc40a1ef6aeac7d04f6ed33e9012 /vespalib | |
parent | 4e32e0bf3f51b0189c4ccbf61320aced80c65e1c (diff) | |
parent | 408cf769c06675b8bffffeeb3447db8ab3c7fc24 (diff) |
Merge pull request #7919 from vespa-engine/vekterli/support-certificate-authorization-mode-env-var-in-cpp-impl
Add support for authorization mode environment variable in C++
Diffstat (limited to 'vespalib')
17 files changed, 193 insertions, 41 deletions
diff --git a/vespalib/src/tests/net/tls/auto_reloading_tls_crypto_engine/auto_reloading_tls_crypto_engine_test.cpp b/vespalib/src/tests/net/tls/auto_reloading_tls_crypto_engine/auto_reloading_tls_crypto_engine_test.cpp index 034dc99b72c..245368b6a7b 100644 --- a/vespalib/src/tests/net/tls/auto_reloading_tls_crypto_engine/auto_reloading_tls_crypto_engine_test.cpp +++ b/vespalib/src/tests/net/tls/auto_reloading_tls_crypto_engine/auto_reloading_tls_crypto_engine_test.cpp @@ -91,10 +91,11 @@ void write_file(vespalib::stringref path, vespalib::stringref data) { struct Fixture { std::unique_ptr<AutoReloadingTlsCryptoEngine> engine; - explicit Fixture(AutoReloadingTlsCryptoEngine::TimeInterval reload_interval) { + explicit Fixture(AutoReloadingTlsCryptoEngine::TimeInterval reload_interval, + AuthorizationMode mode = AuthorizationMode::Enforce) { write_file("test_cert.pem", cert1_pem); // Must be done after file has been written - engine = std::make_unique<AutoReloadingTlsCryptoEngine>("test_config.json", reload_interval); + engine = std::make_unique<AutoReloadingTlsCryptoEngine>("test_config.json", mode, reload_interval); } ~Fixture() { @@ -106,9 +107,17 @@ struct Fixture { vespalib::string current_cert_chain() const { auto impl = engine->acquire_current_engine(); - auto& ctx_impl = dynamic_cast<impl::OpenSslTlsContextImpl&>(*impl->tls_context()); + // Leaks implementation details galore, but it's not very likely that we'll use + // anything but OpenSSL (or compatible APIs) in practice... + auto& ctx_impl = dynamic_cast<const impl::OpenSslTlsContextImpl&>(*impl->tls_context()); return ctx_impl.transport_security_options().cert_chain_pem(); } + + AuthorizationMode current_authorization_mode() const { + auto impl = engine->acquire_current_engine(); + auto& ctx_impl = dynamic_cast<const impl::OpenSslTlsContextImpl&>(*impl->tls_context()); + return ctx_impl.authorization_mode(); + } }; TEST_FF("Config reloading transitively loads updated files", Fixture(50ms), TimeBomb(60)) { @@ -126,4 +135,12 @@ TEST_FF("Config reloading transitively loads updated files", Fixture(50ms), Time // If the config is never reloaded, test will go boom. } +TEST_FF("Shutting down auto-reloading engine immediately stops background thread", Fixture(600s), TimeBomb(60)) { + // This passes just from not having the TimeBomb blow up. +} + +TEST_FF("Authorization mode is propagated to engine", Fixture(50ms, AuthorizationMode::LogOnly), TimeBomb(60)) { + EXPECT_EQUAL(AuthorizationMode::LogOnly, f1.current_authorization_mode()); +} + TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/vespalib/src/tests/net/tls/openssl_impl/openssl_impl_test.cpp b/vespalib/src/tests/net/tls/openssl_impl/openssl_impl_test.cpp index dbfd77aa1c4..69e0d44147e 100644 --- a/vespalib/src/tests/net/tls/openssl_impl/openssl_impl_test.cpp +++ b/vespalib/src/tests/net/tls/openssl_impl/openssl_impl_test.cpp @@ -2,9 +2,10 @@ #include "crypto_utils.h" #include <vespa/vespalib/testkit/test_kit.h> #include <vespa/vespalib/data/smart_buffer.h> +#include <vespa/vespalib/net/tls/authorization_mode.h> +#include <vespa/vespalib/net/tls/crypto_codec.h> #include <vespa/vespalib/net/tls/tls_context.h> #include <vespa/vespalib/net/tls/transport_security_options.h> -#include <vespa/vespalib/net/tls/crypto_codec.h> #include <vespa/vespalib/net/tls/impl/openssl_crypto_codec_impl.h> #include <vespa/vespalib/net/tls/impl/openssl_tls_context_impl.h> #include <vespa/vespalib/test/make_tls_options_for_testing.h> @@ -64,7 +65,7 @@ struct Fixture { Fixture() : tls_opts(vespalib::test::make_tls_options_for_testing()), - tls_ctx(TlsContext::create_default_context(tls_opts)), + tls_ctx(TlsContext::create_default_context(tls_opts, AuthorizationMode::Enforce)), client(create_openssl_codec(tls_ctx, CryptoCodec::Mode::Client)), server(create_openssl_codec(tls_ctx, CryptoCodec::Mode::Server)), client_to_server(64 * 1024), @@ -79,7 +80,7 @@ struct Fixture { static std::unique_ptr<CryptoCodec> create_openssl_codec( const TransportSecurityOptions& opts, CryptoCodec::Mode mode) { - auto ctx = TlsContext::create_default_context(opts); + auto ctx = TlsContext::create_default_context(opts, AuthorizationMode::Enforce); return create_openssl_codec(ctx, mode); } @@ -87,7 +88,7 @@ struct Fixture { const TransportSecurityOptions& opts, std::shared_ptr<CertificateVerificationCallback> cert_verify_callback, CryptoCodec::Mode mode) { - auto ctx = TlsContext::create_default_context(opts, std::move(cert_verify_callback)); + auto ctx = TlsContext::create_default_context(opts, std::move(cert_verify_callback), AuthorizationMode::Enforce); return create_openssl_codec(ctx, mode); } @@ -418,6 +419,15 @@ struct CertFixture : Fixture { return {std::move(cert), std::move(key)}; } + static std::unique_ptr<CryptoCodec> create_openssl_codec_with_authz_mode( + const TransportSecurityOptions& opts, + std::shared_ptr<CertificateVerificationCallback> cert_verify_callback, + CryptoCodec::Mode codec_mode, + AuthorizationMode authz_mode) { + auto ctx = TlsContext::create_default_context(opts, std::move(cert_verify_callback), authz_mode); + return create_openssl_codec(ctx, codec_mode); + } + void reset_client_with_cert_opts(const CertKeyWrapper& ck, AuthorizedPeers authorized) { TransportSecurityOptions client_opts(root_ca.cert->to_pem(), ck.cert->to_pem(), ck.key->private_to_pem(), std::move(authorized)); @@ -439,6 +449,13 @@ struct CertFixture : Fixture { TransportSecurityOptions server_opts(root_ca.cert->to_pem(), ck.cert->to_pem(), ck.key->private_to_pem()); server = create_openssl_codec(server_opts, std::move(cert_cb), CryptoCodec::Mode::Server); } + + void reset_server_with_cert_opts(const CertKeyWrapper& ck, + std::shared_ptr<CertificateVerificationCallback> cert_cb, + AuthorizationMode authz_mode) { + TransportSecurityOptions server_opts(root_ca.cert->to_pem(), ck.cert->to_pem(), ck.key->private_to_pem()); + server = create_openssl_codec_with_authz_mode(server_opts, std::move(cert_cb), CryptoCodec::Mode::Server, authz_mode); + } }; CertFixture::~CertFixture() = default; @@ -585,6 +602,23 @@ TEST_F("Server allows client with certificate that DOES match peer policy", Cert EXPECT_TRUE(f.handshake()); } +void reset_peers_with_server_authz_mode(CertFixture& f, AuthorizationMode authz_mode) { + auto ck = f.create_ca_issued_peer_cert({"hello.world.example.com"}, {}); + + f.reset_client_with_cert_opts(ck, std::make_shared<PrintingCertificateCallback>()); + f.reset_server_with_cert_opts(ck, std::make_shared<AlwaysFailVerifyCallback>(), authz_mode); +} + +TEST_F("Log-only insecure authorization mode ignores verification result", CertFixture) { + reset_peers_with_server_authz_mode(f, AuthorizationMode::LogOnly); + EXPECT_TRUE(f.handshake()); +} + +TEST_F("Disabled insecure authorization mode ignores verification result", CertFixture) { + reset_peers_with_server_authz_mode(f, AuthorizationMode::Disable); + EXPECT_TRUE(f.handshake()); +} + // TODO we can't test embedded nulls since the OpenSSL v3 extension APIs // take in null terminated strings as arguments... :I diff --git a/vespalib/src/vespa/vespalib/net/crypto_engine.cpp b/vespalib/src/vespa/vespalib/net/crypto_engine.cpp index cb779e4a6b0..b771e35dab1 100644 --- a/vespalib/src/vespa/vespalib/net/crypto_engine.cpp +++ b/vespalib/src/vespa/vespalib/net/crypto_engine.cpp @@ -6,6 +6,7 @@ #include <thread> #include <vespa/vespalib/xxhash/xxhash.h> #include <vespa/vespalib/stllike/string.h> +#include <vespa/vespalib/net/tls/authorization_mode.h> #include <vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.h> #include <vespa/vespalib/net/tls/transport_security_options.h> #include <vespa/vespalib/net/tls/transport_security_options_reading.h> @@ -182,14 +183,33 @@ public: } }; +using net::tls::AuthorizationMode; + +AuthorizationMode authorization_mode_from_env() { + const char* env = getenv("VESPA_TLS_INSECURE_AUTHORIZATION_MODE"); + vespalib::string mode = env ? env : ""; + if (mode == "enforce") { + return AuthorizationMode::Enforce; + } else if (mode == "log_only") { + return AuthorizationMode::LogOnly; + } else if (mode == "disable") { + return AuthorizationMode::Disable; + } else if (!mode.empty()) { + LOG(warning, "VESPA_TLS_INSECURE_AUTHORIZATION_MODE environment variable has " + "an unsupported value (%s). Falling back to 'enforce'", mode.c_str()); + } + return AuthorizationMode::Enforce; +} + CryptoEngine::SP create_default_crypto_engine() { const char *env = getenv("VESPA_TLS_CONFIG_FILE"); vespalib::string cfg_file = env ? env : ""; if (cfg_file.empty()) { return std::make_shared<NullCryptoEngine>(); } + auto mode = authorization_mode_from_env(); LOG(debug, "Using TLS crypto engine with config file '%s'", cfg_file.c_str()); - auto tls = std::make_shared<net::tls::AutoReloadingTlsCryptoEngine>(cfg_file); + auto tls = std::make_shared<net::tls::AutoReloadingTlsCryptoEngine>(cfg_file, mode); env = getenv("VESPA_TLS_INSECURE_MIXED_MODE"); vespalib::string mixed_mode = env ? env : ""; if (mixed_mode == "plaintext_client_mixed_server") { diff --git a/vespalib/src/vespa/vespalib/net/tls/CMakeLists.txt b/vespalib/src/vespa/vespalib/net/tls/CMakeLists.txt index 5db7558ef8b..2f8c490b911 100644 --- a/vespalib/src/vespa/vespalib/net/tls/CMakeLists.txt +++ b/vespalib/src/vespa/vespalib/net/tls/CMakeLists.txt @@ -1,6 +1,7 @@ # Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. vespa_add_library(vespalib_vespalib_net_tls OBJECT SOURCES + authorization_mode.cpp auto_reloading_tls_crypto_engine.cpp crypto_codec.cpp crypto_codec_adapter.cpp diff --git a/vespalib/src/vespa/vespalib/net/tls/authorization_mode.cpp b/vespalib/src/vespa/vespalib/net/tls/authorization_mode.cpp new file mode 100644 index 00000000000..05110db0571 --- /dev/null +++ b/vespalib/src/vespa/vespalib/net/tls/authorization_mode.cpp @@ -0,0 +1,23 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "authorization_mode.h" + +#include <iostream> + +namespace vespalib::net::tls { + +const char* enum_name(AuthorizationMode mode) noexcept { + switch (mode) { + case AuthorizationMode::Disable: return "Disable"; + case AuthorizationMode::LogOnly: return "LogOnly"; + case AuthorizationMode::Enforce: return "Enforce"; + } + abort(); +} + +std::ostream& operator<<(std::ostream& os, AuthorizationMode mode) { + os << enum_name(mode); + return os; +} + +} diff --git a/vespalib/src/vespa/vespalib/net/tls/authorization_mode.h b/vespalib/src/vespa/vespalib/net/tls/authorization_mode.h new file mode 100644 index 00000000000..a4d33db7311 --- /dev/null +++ b/vespalib/src/vespa/vespalib/net/tls/authorization_mode.h @@ -0,0 +1,18 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include <iosfwd> + +namespace vespalib::net::tls { + +enum class AuthorizationMode { + Disable, + LogOnly, + Enforce +}; + +const char* enum_name(AuthorizationMode) noexcept; + +std::ostream& operator<<(std::ostream&, AuthorizationMode); + +} diff --git a/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.cpp b/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.cpp index 1b84c98a46d..9e38efabb2b 100644 --- a/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.cpp +++ b/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.cpp @@ -16,14 +16,16 @@ namespace vespalib::net::tls { namespace { -std::shared_ptr<TlsCryptoEngine> tls_engine_from_config_file(const vespalib::string& config_file_path) { +std::shared_ptr<TlsCryptoEngine> tls_engine_from_config_file(const vespalib::string& config_file_path, + AuthorizationMode authz_mode) { auto tls_opts = net::tls::read_options_from_json_file(config_file_path); - return std::make_shared<TlsCryptoEngine>(*tls_opts); + return std::make_shared<TlsCryptoEngine>(*tls_opts, authz_mode); } -std::shared_ptr<TlsCryptoEngine> try_create_engine_from_tls_config(const vespalib::string& config_file_path) { +std::shared_ptr<TlsCryptoEngine> try_create_engine_from_tls_config(const vespalib::string& config_file_path, + AuthorizationMode authz_mode) { try { - return tls_engine_from_config_file(config_file_path); + return tls_engine_from_config_file(config_file_path, authz_mode); } catch (std::exception& e) { LOG(warning, "Failed to reload TLS config file (%s): '%s'. Old config remains in effect.", config_file_path.c_str(), e.what()); @@ -34,13 +36,15 @@ std::shared_ptr<TlsCryptoEngine> try_create_engine_from_tls_config(const vespali } // anonymous namespace AutoReloadingTlsCryptoEngine::AutoReloadingTlsCryptoEngine(vespalib::string config_file_path, + AuthorizationMode mode, TimeInterval reload_interval) - : _thread_mutex(), + : _authorization_mode(mode), + _thread_mutex(), _thread_cond(), _engine_mutex(), _shutdown(false), _config_file_path(std::move(config_file_path)), - _current_engine(tls_engine_from_config_file(_config_file_path)), + _current_engine(tls_engine_from_config_file(_config_file_path, _authorization_mode)), _reload_interval(reload_interval), _reload_thread([this](){ run_reload_loop(); }) { @@ -72,7 +76,7 @@ void AutoReloadingTlsCryptoEngine::run_reload_loop() { } void AutoReloadingTlsCryptoEngine::try_replace_current_engine() { - std::shared_ptr<TlsCryptoEngine> new_engine = try_create_engine_from_tls_config(_config_file_path); + auto new_engine = try_create_engine_from_tls_config(_config_file_path, _authorization_mode); if (new_engine) { std::lock_guard guard(_engine_mutex); _current_engine = std::move(new_engine); diff --git a/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.h b/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.h index 4e3a4074b03..6287fdd4f63 100644 --- a/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.h +++ b/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.h @@ -2,6 +2,7 @@ #pragma once +#include <vespa/vespalib/net/tls/authorization_mode.h> #include <vespa/vespalib/net/tls/tls_crypto_engine.h> #include <vespa/vespalib/stllike/string.h> @@ -17,6 +18,7 @@ public: using EngineSP = std::shared_ptr<TlsCryptoEngine>; using TimeInterval = std::chrono::steady_clock::duration; private: + AuthorizationMode _authorization_mode; mutable std::mutex _thread_mutex; std::condition_variable _thread_cond; mutable std::mutex _engine_mutex; @@ -32,6 +34,7 @@ private: public: explicit AutoReloadingTlsCryptoEngine(vespalib::string config_file_path, + AuthorizationMode mode, TimeInterval reload_interval = std::chrono::seconds(3600)); ~AutoReloadingTlsCryptoEngine() override; diff --git a/vespalib/src/vespa/vespalib/net/tls/impl/openssl_tls_context_impl.cpp b/vespalib/src/vespa/vespalib/net/tls/impl/openssl_tls_context_impl.cpp index 1fa4fc097e0..53ed4d7bdff 100644 --- a/vespalib/src/vespa/vespalib/net/tls/impl/openssl_tls_context_impl.cpp +++ b/vespalib/src/vespa/vespalib/net/tls/impl/openssl_tls_context_impl.cpp @@ -187,8 +187,10 @@ SslCtxPtr new_tls_ctx_with_auto_init() { OpenSslTlsContextImpl::OpenSslTlsContextImpl( const TransportSecurityOptions& ts_opts, - std::shared_ptr<CertificateVerificationCallback> cert_verify_callback) + std::shared_ptr<CertificateVerificationCallback> cert_verify_callback, + AuthorizationMode authz_mode) : _ctx(new_tls_ctx_with_auto_init()), + _authorization_mode(authz_mode), _cert_verify_callback(std::move(cert_verify_callback)), _redacted_transport_options(ts_opts.copy_without_private_key()) { @@ -206,7 +208,7 @@ OpenSslTlsContextImpl::OpenSslTlsContextImpl( disable_compression(); disable_renegotiation(); enforce_peer_certificate_verification(); - set_provided_certificate_verification_callback(); + set_ssl_ctx_self_reference(); // TODO set accepted cipher suites! // TODO `--> If not set in options, use Modern spec from https://wiki.mozilla.org/Security/Server_Side_TLS } @@ -385,6 +387,8 @@ bool fill_certificate_subject_alternate_names(::X509* cert, PeerCredentials& cre return true; } +} // anon ns + // TODO if/when we want to move per-connection peer credentials into the crypto codec/socket // itself, we probably need to set the verification callback (data) on _SSL_, not _SSL_CTX_..! // Note: we try to be as conservative as possible. If anything looks out of place, we fail @@ -393,7 +397,7 @@ bool fill_certificate_subject_alternate_names(::X509* cert, PeerCredentials& cre // References: // https://github.com/boostorg/asio/blob/develop/include/boost/asio/ssl/impl/context.ipp // https://github.com/boostorg/asio/blob/develop/include/boost/asio/ssl/impl/rfc2818_verification.ipp -int verify_cb_wrapper(int preverified_ok, ::X509_STORE_CTX* store_ctx) { +int OpenSslTlsContextImpl::verify_cb_wrapper(int preverified_ok, ::X509_STORE_CTX* store_ctx) { if (!preverified_ok) { return 0; // If it's already known to be broken, we won't do anything more. } @@ -415,10 +419,15 @@ int verify_cb_wrapper(int preverified_ok, ::X509_STORE_CTX* store_ctx) { if (!ssl_ctx) { return 0; } - auto* cert_validator = static_cast<CertificateVerificationCallback*>(SSL_CTX_get_app_data(ssl_ctx)); - if (!cert_validator) { + auto* self = static_cast<OpenSslTlsContextImpl*>(SSL_CTX_get_app_data(ssl_ctx)); + if (!self) { return 0; } + const auto authz_mode = self->authorization_mode(); + // TODO consider if we want to fill in peer credentials even if authorization is disabled + if (authz_mode == AuthorizationMode::Disable) { + return 1; + } ::X509* cert = ::X509_STORE_CTX_get_current_cert(store_ctx); // _not_ owned by us if (!cert) { LOG(error, "Got X509_STORE_CTX with preverified_ok == 1 but no current cert"); @@ -432,10 +441,12 @@ int verify_cb_wrapper(int preverified_ok, ::X509_STORE_CTX* store_ctx) { return 0; } try { - const bool verified_by_cb = cert_validator->verify(creds); + const bool verified_by_cb = self->_cert_verify_callback->verify(creds); if (!verified_by_cb) { - LOG(debug, "Connection rejected by certificate verification callback"); - return 0; + // TODO we should print the peer's remote address too, but that information is + // not currently available to us here. + LOG(warning, "Certificate verification failed for %s", to_string(creds).c_str()); + return (authz_mode == AuthorizationMode::Enforce) ? 0 : 1; } } catch (std::exception& e) { LOG(error, "Got exception during certificate verification callback: %s", e.what()); @@ -444,16 +455,14 @@ int verify_cb_wrapper(int preverified_ok, ::X509_STORE_CTX* store_ctx) { return 1; } -} // anon ns - void OpenSslTlsContextImpl::enforce_peer_certificate_verification() { // We require full mutual certificate verification. No way to configure // out of this, at least not for the time being. ::SSL_CTX_set_verify(_ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb_wrapper); } -void OpenSslTlsContextImpl::set_provided_certificate_verification_callback() { - SSL_CTX_set_app_data(_ctx.get(), _cert_verify_callback.get()); +void OpenSslTlsContextImpl::set_ssl_ctx_self_reference() { + SSL_CTX_set_app_data(_ctx.get(), this); } } diff --git a/vespalib/src/vespa/vespalib/net/tls/impl/openssl_tls_context_impl.h b/vespalib/src/vespa/vespalib/net/tls/impl/openssl_tls_context_impl.h index 5dddbc80ef2..757204325b0 100644 --- a/vespalib/src/vespa/vespalib/net/tls/impl/openssl_tls_context_impl.h +++ b/vespalib/src/vespa/vespalib/net/tls/impl/openssl_tls_context_impl.h @@ -11,11 +11,13 @@ namespace vespalib::net::tls::impl { class OpenSslTlsContextImpl : public TlsContext { SslCtxPtr _ctx; + AuthorizationMode _authorization_mode; std::shared_ptr<CertificateVerificationCallback> _cert_verify_callback; TransportSecurityOptions _redacted_transport_options; public: OpenSslTlsContextImpl(const TransportSecurityOptions& ts_opts, - std::shared_ptr<CertificateVerificationCallback> cert_verify_callback); + std::shared_ptr<CertificateVerificationCallback> cert_verify_callback, + AuthorizationMode authz_mode); ~OpenSslTlsContextImpl() override; ::SSL_CTX* native_context() const noexcept { return _ctx.get(); } @@ -24,6 +26,8 @@ public: const TransportSecurityOptions& transport_security_options() const noexcept { return _redacted_transport_options; } + // AuthorizationMode this context was created with + AuthorizationMode authorization_mode() const noexcept { return _authorization_mode; } private: // Note: single use per instance; does _not_ clear existing chain! void add_certificate_authorities(stringref ca_pem); @@ -39,7 +43,9 @@ private: // explicitly to the peer that it's not a supported action. void disable_renegotiation(); void enforce_peer_certificate_verification(); - void set_provided_certificate_verification_callback(); + void set_ssl_ctx_self_reference(); + + static int verify_cb_wrapper(int preverified_ok, ::X509_STORE_CTX* store_ctx); }; } diff --git a/vespalib/src/vespa/vespalib/net/tls/peer_credentials.cpp b/vespalib/src/vespa/vespalib/net/tls/peer_credentials.cpp index e8351aa38f3..b7e6fd2224e 100644 --- a/vespalib/src/vespa/vespalib/net/tls/peer_credentials.cpp +++ b/vespalib/src/vespa/vespalib/net/tls/peer_credentials.cpp @@ -1,7 +1,9 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "peer_credentials.h" +#include <vespa/vespalib/stllike/asciistream.h> #include <iostream> +#include <sstream> namespace vespalib::net::tls { @@ -9,16 +11,22 @@ PeerCredentials::PeerCredentials() = default; PeerCredentials::~PeerCredentials() = default; std::ostream& operator<<(std::ostream& os, const PeerCredentials& creds) { + os << to_string(creds); + return os; +} + +vespalib::string to_string(const PeerCredentials& creds) { + vespalib::asciistream os; os << "PeerCredentials(CN '" << creds.common_name - << "', DNS SANs {"; + << "', DNS SANs ["; for (size_t i = 0; i < creds.dns_sans.size(); ++i) { if (i != 0) { os << ", "; } os << '\'' << creds.dns_sans[i] << '\''; } - os << "})"; - return os; + os << "])"; + return os.str(); } } diff --git a/vespalib/src/vespa/vespalib/net/tls/peer_credentials.h b/vespalib/src/vespa/vespalib/net/tls/peer_credentials.h index 4402244cc18..93e5554a86e 100644 --- a/vespalib/src/vespa/vespalib/net/tls/peer_credentials.h +++ b/vespalib/src/vespa/vespalib/net/tls/peer_credentials.h @@ -21,4 +21,6 @@ struct PeerCredentials { std::ostream& operator<<(std::ostream&, const PeerCredentials&); +vespalib::string to_string(const PeerCredentials&); + } diff --git a/vespalib/src/vespa/vespalib/net/tls/policy_checking_certificate_verifier.h b/vespalib/src/vespa/vespalib/net/tls/policy_checking_certificate_verifier.h index 6e7ea44861a..44db335eed6 100644 --- a/vespalib/src/vespa/vespalib/net/tls/policy_checking_certificate_verifier.h +++ b/vespalib/src/vespa/vespalib/net/tls/policy_checking_certificate_verifier.h @@ -1,6 +1,7 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once +#include "authorization_mode.h" #include "certificate_verification_callback.h" #include "peer_policies.h" diff --git a/vespalib/src/vespa/vespalib/net/tls/tls_context.cpp b/vespalib/src/vespa/vespalib/net/tls/tls_context.cpp index c02ed5aed4a..5b57414fde4 100644 --- a/vespalib/src/vespa/vespalib/net/tls/tls_context.cpp +++ b/vespalib/src/vespa/vespalib/net/tls/tls_context.cpp @@ -6,15 +6,17 @@ namespace vespalib::net::tls { -std::shared_ptr<TlsContext> TlsContext::create_default_context(const TransportSecurityOptions& opts) { +std::shared_ptr<TlsContext> TlsContext::create_default_context(const TransportSecurityOptions& opts, + AuthorizationMode authz_mode) { auto verifier = create_verify_callback_from(opts.authorized_peers()); - return std::make_shared<impl::OpenSslTlsContextImpl>(opts, std::move(verifier)); + return std::make_shared<impl::OpenSslTlsContextImpl>(opts, std::move(verifier), authz_mode); } std::shared_ptr<TlsContext> TlsContext::create_default_context( const TransportSecurityOptions& opts, - std::shared_ptr<CertificateVerificationCallback> cert_verify_callback) { - return std::make_shared<impl::OpenSslTlsContextImpl>(opts, std::move(cert_verify_callback)); + std::shared_ptr<CertificateVerificationCallback> cert_verify_callback, + AuthorizationMode authz_mode) { + return std::make_shared<impl::OpenSslTlsContextImpl>(opts, std::move(cert_verify_callback), authz_mode); } } diff --git a/vespalib/src/vespa/vespalib/net/tls/tls_context.h b/vespalib/src/vespa/vespalib/net/tls/tls_context.h index ff9ee91f7da..04538694ee7 100644 --- a/vespalib/src/vespa/vespalib/net/tls/tls_context.h +++ b/vespalib/src/vespa/vespalib/net/tls/tls_context.h @@ -1,6 +1,7 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once +#include "authorization_mode.h" #include <memory> namespace vespalib::net::tls { @@ -13,14 +14,16 @@ struct TlsContext { // Create a TLS context which verifies certificates according to the provided options' // CA trust roots AND authorized peer policies - static std::shared_ptr<TlsContext> create_default_context(const TransportSecurityOptions&); + static std::shared_ptr<TlsContext> create_default_context(const TransportSecurityOptions&, + AuthorizationMode); // Create a TLS context where the certificate verification callback is explicitly provided. // IMPORTANT: This does NOT verify that the peer satisfies the authorized peer policies! // It only verifies that a peer is signed by a trusted CA. This function should // therefore only be used in very special circumstances, such as unit tests. static std::shared_ptr<TlsContext> create_default_context( const TransportSecurityOptions&, - std::shared_ptr<CertificateVerificationCallback> cert_verify_callback); + std::shared_ptr<CertificateVerificationCallback> cert_verify_callback, + AuthorizationMode); }; } diff --git a/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.cpp b/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.cpp index 912fea534b2..7d0d3287965 100644 --- a/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.cpp +++ b/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.cpp @@ -6,8 +6,8 @@ namespace vespalib { -TlsCryptoEngine::TlsCryptoEngine(net::tls::TransportSecurityOptions tls_opts) - : _tls_ctx(net::tls::TlsContext::create_default_context(tls_opts)) +TlsCryptoEngine::TlsCryptoEngine(net::tls::TransportSecurityOptions tls_opts, net::tls::AuthorizationMode authz_mode) + : _tls_ctx(net::tls::TlsContext::create_default_context(tls_opts, authz_mode)) { } diff --git a/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.h b/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.h index 151b3ef128b..dc7d7eaf9ce 100644 --- a/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.h +++ b/vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.h @@ -22,7 +22,8 @@ class TlsCryptoEngine : public AbstractTlsCryptoEngine private: std::shared_ptr<net::tls::TlsContext> _tls_ctx; public: - explicit TlsCryptoEngine(net::tls::TransportSecurityOptions tls_opts); + explicit TlsCryptoEngine(net::tls::TransportSecurityOptions tls_opts, + net::tls::AuthorizationMode authz_mode = net::tls::AuthorizationMode::Enforce); std::unique_ptr<TlsCryptoSocket> create_tls_crypto_socket(SocketHandle socket, bool is_server) override; CryptoSocket::UP create_crypto_socket(SocketHandle socket, bool is_server) override { return create_tls_crypto_socket(std::move(socket), is_server); |