summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHåvard Pettersen <havardpe@oath.com>2018-09-27 15:39:34 +0000
committerHåvard Pettersen <havardpe@oath.com>2018-09-27 16:11:07 +0000
commit763f8e2f35a76bbc15df66843162400fbe136a56 (patch)
treed9840b55b8bfcee4ed76a39d7b933e9d78e08064
parentf905c1d6993b22ca5132e10bacd21761c35b5fc5 (diff)
mixed mode tls support in fnet
-rw-r--r--fnet/src/tests/frt/rpc/CMakeLists.txt4
-rw-r--r--fnet/src/tests/frt/rpc/my_crypto_engine.hpp10
-rw-r--r--searchcore/src/vespa/searchcore/fdispatch/program/fdispatch.cpp2
-rw-r--r--searchlib/src/vespa/searchlib/engine/transportserver.cpp2
-rw-r--r--vespalib/src/vespa/vespalib/net/crypto_engine.cpp17
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/CMakeLists.txt3
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/crypto_codec_adapter.cpp10
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/crypto_codec_adapter.h5
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.cpp20
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.h34
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_socket.cpp94
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_socket.h35
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/tls_crypto_socket.cpp9
-rw-r--r--vespalib/src/vespa/vespalib/net/tls/tls_crypto_socket.h14
14 files changed, 253 insertions, 6 deletions
diff --git a/fnet/src/tests/frt/rpc/CMakeLists.txt b/fnet/src/tests/frt/rpc/CMakeLists.txt
index 2bacd37686a..6aa2e073e4e 100644
--- a/fnet/src/tests/frt/rpc/CMakeLists.txt
+++ b/fnet/src/tests/frt/rpc/CMakeLists.txt
@@ -8,6 +8,8 @@ vespa_add_executable(fnet_invoke_test_app TEST
vespa_add_test(NAME fnet_invoke_test_app COMMAND fnet_invoke_test_app)
vespa_add_test(NAME fnet_invoke_test_app_xor COMMAND fnet_invoke_test_app ENVIRONMENT "CRYPTOENGINE=xor")
vespa_add_test(NAME fnet_invoke_test_app_tls COMMAND fnet_invoke_test_app ENVIRONMENT "CRYPTOENGINE=tls")
+vespa_add_test(NAME fnet_invoke_test_app_tls_maybe_yes COMMAND fnet_invoke_test_app ENVIRONMENT "CRYPTOENGINE=tls_maybe_yes")
+vespa_add_test(NAME fnet_invoke_test_app_tls_maybe_no COMMAND fnet_invoke_test_app ENVIRONMENT "CRYPTOENGINE=tls_maybe_no")
vespa_add_executable(fnet_detach_return_invoke_test_app TEST
SOURCES
detach_return_invoke.cpp
@@ -24,6 +26,8 @@ vespa_add_executable(fnet_session_test_app TEST
vespa_add_test(NAME fnet_session_test_app COMMAND fnet_session_test_app)
vespa_add_test(NAME fnet_session_test_app_xor COMMAND fnet_session_test_app ENVIRONMENT "CRYPTOENGINE=xor")
vespa_add_test(NAME fnet_session_test_app_tls COMMAND fnet_session_test_app ENVIRONMENT "CRYPTOENGINE=tls")
+vespa_add_test(NAME fnet_session_test_app_tls_maybe_yes COMMAND fnet_session_test_app ENVIRONMENT "CRYPTOENGINE=tls_maybe_yes")
+vespa_add_test(NAME fnet_session_test_app_tls_maybe_no COMMAND fnet_session_test_app ENVIRONMENT "CRYPTOENGINE=tls_maybe_no")
vespa_add_executable(fnet_sharedblob_test_app TEST
SOURCES
sharedblob.cpp
diff --git a/fnet/src/tests/frt/rpc/my_crypto_engine.hpp b/fnet/src/tests/frt/rpc/my_crypto_engine.hpp
index 6cd8d47e917..51811f4f70c 100644
--- a/fnet/src/tests/frt/rpc/my_crypto_engine.hpp
+++ b/fnet/src/tests/frt/rpc/my_crypto_engine.hpp
@@ -1,6 +1,8 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/vespalib/net/crypto_engine.h>
#include <vespa/vespalib/net/tls/tls_crypto_engine.h>
+#include <vespa/vespalib/net/tls/maybe_tls_crypto_engine.h>
#include <vespa/vespalib/test/make_tls_options_for_testing.h>
vespalib::CryptoEngine::SP my_crypto_engine() {
@@ -16,6 +18,14 @@ vespalib::CryptoEngine::SP my_crypto_engine() {
} else if (engine == "tls") {
fprintf(stderr, "crypto engine: tls\n");
return std::make_shared<vespalib::TlsCryptoEngine>(vespalib::test::make_tls_options_for_testing());
+ } else if (engine == "tls_maybe_yes") {
+ fprintf(stderr, "crypto engine: tls client, mixed server\n");
+ auto tls = std::make_shared<vespalib::TlsCryptoEngine>(vespalib::test::make_tls_options_for_testing());
+ return std::make_shared<vespalib::MaybeTlsCryptoEngine>(std::move(tls), true);
+ } else if (engine == "tls_maybe_no") {
+ fprintf(stderr, "crypto engine: null client, mixed server\n");
+ auto tls = std::make_shared<vespalib::TlsCryptoEngine>(vespalib::test::make_tls_options_for_testing());
+ return std::make_shared<vespalib::MaybeTlsCryptoEngine>(std::move(tls), false);
}
TEST_FATAL(("invalid crypto engine: " + engine).c_str());
abort();
diff --git a/searchcore/src/vespa/searchcore/fdispatch/program/fdispatch.cpp b/searchcore/src/vespa/searchcore/fdispatch/program/fdispatch.cpp
index b85e706397d..9dd4e81f91a 100644
--- a/searchcore/src/vespa/searchcore/fdispatch/program/fdispatch.cpp
+++ b/searchcore/src/vespa/searchcore/fdispatch/program/fdispatch.cpp
@@ -297,7 +297,7 @@ Fdispatch::Init()
LOG(debug, "Creating FNET transport");
- _transport = std::make_unique<FNET_Transport>(std::make_shared<vespalib::NullCryptoEngine>(), _config->transportthreads); // disable encryption
+ _transport = std::make_unique<FNET_Transport>(_config->transportthreads);
// grab node slowness limit defaults
diff --git a/searchlib/src/vespa/searchlib/engine/transportserver.cpp b/searchlib/src/vespa/searchlib/engine/transportserver.cpp
index bc739a7bf48..0fa7d44bbad 100644
--- a/searchlib/src/vespa/searchlib/engine/transportserver.cpp
+++ b/searchlib/src/vespa/searchlib/engine/transportserver.cpp
@@ -359,7 +359,7 @@ TransportServer::TransportServer(SearchServer &searchServer,
: _searchServer(searchServer),
_docsumServer(docsumServer),
_monitorServer(monitorServer),
- _transport(std::make_shared<vespalib::NullCryptoEngine>(), 1), // disable encryption
+ _transport(),
_ready(false),
_failed(false),
_doListen(true),
diff --git a/vespalib/src/vespa/vespalib/net/crypto_engine.cpp b/vespalib/src/vespa/vespalib/net/crypto_engine.cpp
index 3dd800dadf0..d45b0cea1c5 100644
--- a/vespalib/src/vespa/vespalib/net/crypto_engine.cpp
+++ b/vespalib/src/vespa/vespalib/net/crypto_engine.cpp
@@ -9,6 +9,7 @@
#include <vespa/vespalib/net/tls/transport_security_options.h>
#include <vespa/vespalib/net/tls/transport_security_options_reading.h>
#include <vespa/vespalib/net/tls/tls_crypto_engine.h>
+#include <vespa/vespalib/net/tls/maybe_tls_crypto_engine.h>
#include <vespa/vespalib/data/smart_buffer.h>
#include <assert.h>
@@ -175,10 +176,22 @@ CryptoEngine::SP create_default_crypto_engine() {
if (cfg_file.empty()) {
return std::make_shared<NullCryptoEngine>();
}
-
LOG(debug, "Using TLS crypto engine with config file '%s'", cfg_file.c_str());
auto tls_opts = net::tls::read_options_from_json_file(cfg_file);
- return std::make_shared<TlsCryptoEngine>(*tls_opts);
+ auto tls = std::make_shared<TlsCryptoEngine>(*tls_opts);
+ env = getenv("VESPA_TLS_INSECURE_MIXED_MODE");
+ vespalib::string mixed_mode = env ? env : "";
+ if (mixed_mode == "plaintext_client_mixed_server") {
+ LOG(debug, "tls insecure mixed-mode activated: plaintext client, mixed server");
+ return std::make_shared<MaybeTlsCryptoEngine>(std::move(tls), false);
+ } else if (mixed_mode == "tls_client_mixed_server") {
+ LOG(debug, "tls insecure mixed-mode activated: tls client, mixed server");
+ return std::make_shared<MaybeTlsCryptoEngine>(std::move(tls), true);
+ } else if (!mixed_mode.empty()) {
+ LOG(warning, "bad tls insecure mixed-mode specified: '%s' (ignoring)",
+ mixed_mode.c_str());
+ }
+ return tls;
}
} // namespace vespalib::<unnamed>
diff --git a/vespalib/src/vespa/vespalib/net/tls/CMakeLists.txt b/vespalib/src/vespa/vespalib/net/tls/CMakeLists.txt
index 17abd82366d..87b7cff1c13 100644
--- a/vespalib/src/vespa/vespalib/net/tls/CMakeLists.txt
+++ b/vespalib/src/vespa/vespalib/net/tls/CMakeLists.txt
@@ -4,9 +4,12 @@ vespa_add_library(vespalib_vespalib_net_tls OBJECT
crypto_codec.cpp
crypto_codec_adapter.cpp
crypto_exception.cpp
+ maybe_tls_crypto_engine.cpp
+ maybe_tls_crypto_socket.cpp
protocol_snooping.cpp
tls_context.cpp
tls_crypto_engine.cpp
+ tls_crypto_socket.cpp
transport_security_options.cpp
transport_security_options_reading.cpp
DEPENDS
diff --git a/vespalib/src/vespa/vespalib/net/tls/crypto_codec_adapter.cpp b/vespalib/src/vespa/vespalib/net/tls/crypto_codec_adapter.cpp
index 494919f449f..28aede69d22 100644
--- a/vespalib/src/vespa/vespalib/net/tls/crypto_codec_adapter.cpp
+++ b/vespalib/src/vespa/vespalib/net/tls/crypto_codec_adapter.cpp
@@ -56,6 +56,16 @@ CryptoCodecAdapter::flush_all()
return res;
}
+void
+CryptoCodecAdapter::inject_read_data(const char *buf, size_t len)
+{
+ if (len > 0) {
+ auto dst = _input.reserve(len);
+ memcpy(dst.data, buf, len);
+ _input.commit(len);
+ }
+}
+
CryptoSocket::HandshakeResult
CryptoCodecAdapter::handshake()
{
diff --git a/vespalib/src/vespa/vespalib/net/tls/crypto_codec_adapter.h b/vespalib/src/vespa/vespalib/net/tls/crypto_codec_adapter.h
index 29996a9abbb..af2db3525d3 100644
--- a/vespalib/src/vespa/vespalib/net/tls/crypto_codec_adapter.h
+++ b/vespalib/src/vespa/vespalib/net/tls/crypto_codec_adapter.h
@@ -2,7 +2,7 @@
#pragma once
-#include <vespa/vespalib/net/crypto_socket.h>
+#include "tls_crypto_socket.h"
#include <vespa/vespalib/net/socket_handle.h>
#include <vespa/vespalib/data/smart_buffer.h>
#include "crypto_codec.h"
@@ -13,7 +13,7 @@ namespace vespalib::net::tls {
* Component adapting an underlying CryptoCodec to the CryptoSocket
* interface by performing buffer and socket management.
**/
-class CryptoCodecAdapter : public CryptoSocket
+class CryptoCodecAdapter : public TlsCryptoSocket
{
private:
SmartBuffer _input;
@@ -31,6 +31,7 @@ private:
public:
CryptoCodecAdapter(SocketHandle socket, std::unique_ptr<CryptoCodec> codec)
: _input(64 * 1024), _output(64 * 1024), _socket(std::move(socket)), _codec(std::move(codec)) {}
+ void inject_read_data(const char *buf, size_t len) override;
int get_fd() const override { return _socket.get(); }
HandshakeResult handshake() override;
size_t min_read_buffer_size() const override { return _codec->min_decode_buffer_size(); }
diff --git a/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.cpp b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.cpp
new file mode 100644
index 00000000000..891f8cdab23
--- /dev/null
+++ b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.cpp
@@ -0,0 +1,20 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "maybe_tls_crypto_engine.h"
+#include "maybe_tls_crypto_socket.h"
+
+namespace vespalib {
+
+CryptoSocket::UP
+MaybeTlsCryptoEngine::create_crypto_socket(SocketHandle socket, bool is_server)
+{
+ if (is_server) {
+ return std::make_unique<MaybeTlsCryptoSocket>(std::move(socket), _tls_engine);
+ } else if (_use_tls_when_client) {
+ return _tls_engine->create_crypto_socket(std::move(socket), false);
+ } else {
+ return _null_engine->create_crypto_socket(std::move(socket), false);
+ }
+}
+
+} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.h b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.h
new file mode 100644
index 00000000000..8e76460231c
--- /dev/null
+++ b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_engine.h
@@ -0,0 +1,34 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <memory>
+#include "tls_crypto_engine.h"
+#include <vespa/vespalib/net/crypto_engine.h>
+
+namespace vespalib {
+
+/**
+ * A crypto engine that supports both tls encrypted connections and
+ * unencrypted connections. The use of tls for incoming connections is
+ * auto-detected using clever heuristics. The use of tls for outgoing
+ * connections is controlled by the use_tls_when_client flag given to
+ * the constructor.
+ **/
+class MaybeTlsCryptoEngine : public CryptoEngine
+{
+private:
+ std::shared_ptr<NullCryptoEngine> _null_engine;
+ std::shared_ptr<TlsCryptoEngine> _tls_engine;
+ bool _use_tls_when_client;
+
+public:
+ MaybeTlsCryptoEngine(std::shared_ptr<TlsCryptoEngine> tls_engine,
+ bool use_tls_when_client)
+ : _null_engine(std::make_shared<NullCryptoEngine>()),
+ _tls_engine(std::move(tls_engine)),
+ _use_tls_when_client(use_tls_when_client) {}
+ CryptoSocket::UP create_crypto_socket(SocketHandle socket, bool is_server) override;
+};
+
+} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_socket.cpp b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_socket.cpp
new file mode 100644
index 00000000000..2c3b2e0bdcc
--- /dev/null
+++ b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_socket.cpp
@@ -0,0 +1,94 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "maybe_tls_crypto_socket.h"
+#include "tls_crypto_socket.h"
+#include "protocol_snooping.h"
+#include <vespa/vespalib/data/smart_buffer.h>
+#include <cassert>
+
+namespace vespalib {
+
+namespace {
+
+class MyCryptoSocket : public CryptoSocket
+{
+private:
+ static constexpr size_t SNOOP_SIZE = net::tls::snooping::min_header_bytes_to_observe();
+
+ CryptoSocket::UP &_self;
+ SocketHandle _socket;
+ std::shared_ptr<TlsCryptoEngine> _factory;
+ SmartBuffer _buffer;
+
+ bool is_blocked(ssize_t res, int error) const {
+ return ((res < 0) && ((error == EWOULDBLOCK) || (error == EAGAIN)));
+ }
+
+ bool looksLikeTlsToMe(const char *buf) {
+ return (net::tls::snooping::snoop_client_hello_header(buf) == net::tls::snooping::TlsSnoopingResult::ProbablyTls);
+ }
+
+public:
+ MyCryptoSocket(CryptoSocket::UP &self, SocketHandle socket, std::shared_ptr<TlsCryptoEngine> tls_engine)
+ : _self(self), _socket(std::move(socket)), _factory(std::move(tls_engine)), _buffer(4096)
+ {
+ assert(SNOOP_SIZE > 0); // we read before checking this
+ assert(SNOOP_SIZE <= 8); // we promise this in our comment
+ }
+ int get_fd() const override { return _socket.get(); }
+ HandshakeResult handshake() override {
+ if (_factory) {
+ auto dst = _buffer.reserve(SNOOP_SIZE);
+ ssize_t res = _socket.read(dst.data, dst.size);
+ if (res > 0) {
+ _buffer.commit(res);
+ } else if (!is_blocked(res, errno)) {
+ return HandshakeResult::FAIL;
+ }
+ auto src = _buffer.obtain();
+ if (src.size < SNOOP_SIZE) {
+ return HandshakeResult::NEED_READ;
+ }
+ if (looksLikeTlsToMe(src.data)) {
+ CryptoSocket::UP &self = _self; // need copy due to self destruction
+ auto tls_socket = _factory->create_crypto_socket(std::move(_socket), true);
+ TlsCryptoSocket *covariant = dynamic_cast<TlsCryptoSocket*>(tls_socket.get());
+ assert(covariant != nullptr);
+ covariant->inject_read_data(src.data, src.size);
+ self = std::move(tls_socket);
+ return self->handshake();
+ } else {
+ _factory.reset();
+ }
+ }
+ return HandshakeResult::DONE;
+ }
+ size_t min_read_buffer_size() const override { return 1; }
+ ssize_t read(char *buf, size_t len) override {
+ int drain_result = drain(buf, len);
+ if (drain_result != 0) {
+ return drain_result;
+ }
+ return _socket.read(buf, len);
+ }
+ ssize_t drain(char *buf, size_t len) override {
+ auto src = _buffer.obtain();
+ size_t frame = std::min(len, src.size);
+ if (frame > 0) {
+ memcpy(buf, src.data, frame);
+ _buffer.evict(frame);
+ }
+ return frame;
+ }
+ ssize_t write(const char *buf, size_t len) override { return _socket.write(buf, len); }
+ ssize_t flush() override { return 0; }
+};
+
+} // namespace vespalib::<unnamed>
+
+MaybeTlsCryptoSocket::MaybeTlsCryptoSocket(SocketHandle socket, std::shared_ptr<TlsCryptoEngine> tls_engine)
+ : _socket(std::make_unique<MyCryptoSocket>(_socket, std::move(socket), std::move(tls_engine)))
+{
+}
+
+} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_socket.h b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_socket.h
new file mode 100644
index 00000000000..3c7963cc948
--- /dev/null
+++ b/vespalib/src/vespa/vespalib/net/tls/maybe_tls_crypto_socket.h
@@ -0,0 +1,35 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <memory>
+#include <vespa/vespalib/net/crypto_socket.h>
+#include <vespa/vespalib/net/socket_handle.h>
+#include "tls_crypto_engine.h"
+
+namespace vespalib {
+
+/**
+ * A crypto socket for the server side of a connection that
+ * auto-detects whether the connection is tls encrypted or unencrypted
+ * using clever heuristics. The assumption is that the client side
+ * will send at least 8 bytes of data before expecting anything from
+ * the server. These 8 bytes are inspected to see if they look like
+ * part of a tls handshake or not.
+ **/
+class MaybeTlsCryptoSocket : public CryptoSocket
+{
+private:
+ CryptoSocket::UP _socket;
+public:
+ MaybeTlsCryptoSocket(SocketHandle socket, std::shared_ptr<TlsCryptoEngine> tls_engine);
+ int get_fd() const override { return _socket->get_fd(); }
+ HandshakeResult handshake() override { return _socket->handshake(); }
+ size_t min_read_buffer_size() const override { return _socket->min_read_buffer_size(); }
+ ssize_t read(char *buf, size_t len) override { return _socket->read(buf, len); }
+ ssize_t drain(char *buf, size_t len) override { return _socket->drain(buf, len); }
+ ssize_t write(const char *buf, size_t len) override { return _socket->write(buf, len); }
+ ssize_t flush() override { return _socket->flush(); }
+};
+
+} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/net/tls/tls_crypto_socket.cpp b/vespalib/src/vespa/vespalib/net/tls/tls_crypto_socket.cpp
new file mode 100644
index 00000000000..ee93827898e
--- /dev/null
+++ b/vespalib/src/vespa/vespalib/net/tls/tls_crypto_socket.cpp
@@ -0,0 +1,9 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "tls_crypto_socket.h"
+
+namespace vespalib {
+
+TlsCryptoSocket::~TlsCryptoSocket() = default;
+
+} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/net/tls/tls_crypto_socket.h b/vespalib/src/vespa/vespalib/net/tls/tls_crypto_socket.h
new file mode 100644
index 00000000000..c98af6ee651
--- /dev/null
+++ b/vespalib/src/vespa/vespalib/net/tls/tls_crypto_socket.h
@@ -0,0 +1,14 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/vespalib/net/crypto_socket.h>
+
+namespace vespalib {
+
+struct TlsCryptoSocket : public CryptoSocket {
+ ~TlsCryptoSocket();
+ virtual void inject_read_data(const char *buf, size_t len) = 0;
+};
+
+} // namespace vespalib