summaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorTor Brede Vekterli <vekterli@oath.com>2018-12-11 14:53:58 +0100
committerGitHub <noreply@github.com>2018-12-11 14:53:58 +0100
commita4af8e7aa38507b43fa0cb75c8af18f42203a3f3 (patch)
treeeb21bc813ac7cc40a1ef6aeac7d04f6ed33e9012 /vespalib
parent4e32e0bf3f51b0189c4ccbf61320aced80c65e1c (diff)
parent408cf769c06675b8bffffeeb3447db8ab3c7fc24 (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')
-rw-r--r--vespalib/src/tests/net/tls/auto_reloading_tls_crypto_engine/auto_reloading_tls_crypto_engine_test.cpp23
-rw-r--r--vespalib/src/tests/net/tls/openssl_impl/openssl_impl_test.cpp42
-rw-r--r--vespalib/src/vespa/vespalib/net/crypto_engine.cpp22
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/CMakeLists.txt1
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/authorization_mode.cpp23
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/authorization_mode.h18
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.cpp18
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.h3
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/impl/openssl_tls_context_impl.cpp33
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/impl/openssl_tls_context_impl.h10
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/peer_credentials.cpp14
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/peer_credentials.h2
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/policy_checking_certificate_verifier.h1
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/tls_context.cpp10
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/tls_context.h7
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.cpp4
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/tls_crypto_engine.h3
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);