aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <[email protected]>2015-01-10 22:44:30 +0000
committerlloyd <[email protected]>2015-01-10 22:44:30 +0000
commit5becd02f3aa5ad7e12958bc20b8fbc8816561e32 (patch)
tree27dbbcd792af2cf5ac511690363d714615b52499
parentef2c4e617de1105a031560a65d18972c0c3ef030 (diff)
Convert the asio server from a weird example server to a generic proxy server.
-rw-r--r--doc/manual/tls.rst10
-rw-r--r--doc/relnotes/1_11_13.rst5
-rw-r--r--src/cmd/tls_proxy.cpp592
-rw-r--r--src/cmd/tls_server_asio.cpp326
4 files changed, 599 insertions, 334 deletions
diff --git a/doc/manual/tls.rst b/doc/manual/tls.rst
index b3ec1c0ea..1b7929f1b 100644
--- a/doc/manual/tls.rst
+++ b/doc/manual/tls.rst
@@ -269,9 +269,7 @@ TLS Clients
resized as needed to process inputs). Otherwise some reasonable
default is used.
-A simple TLS client example:
-
-.. literalinclude:: ../../src/cmd/tls_client.cpp
+A TLS client example using BSD sockets is in `src/cmd/tls_client.cpp`
TLS Servers
----------------------------------------
@@ -309,10 +307,8 @@ not until they actually receive a hello without this parameter.
renegotiation, but might change across different connections using
that session.
-An example TLS server that can handle concurrent connections using
-asio follows:
-
-.. literalinclude:: ../../src/cmd/tls_server_asio.cpp
+An example TLS server implementation using asio is available in
+`src/cmd/tls_proxy.cpp`.
.. _tls_sessions:
diff --git a/doc/relnotes/1_11_13.rst b/doc/relnotes/1_11_13.rst
index 8a9ed5872..d0ca04245 100644
--- a/doc/relnotes/1_11_13.rst
+++ b/doc/relnotes/1_11_13.rst
@@ -1,6 +1,9 @@
Version 1.11.13, Not Yet Released
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+* The command line tool now has `tls_proxy` which negotiates TLS with
+ clients and forwards the plaintext to a specified port.
+
* Add MCEIES, a McEliece-based integrated encryption system using
AES-256 in OCB mode for message encryption/authentication.
@@ -9,7 +12,7 @@ Version 1.11.13, Not Yet Released
* Add SHA-512/256
* The format of serialized TLS sessions has changed. Additiionally, PEM
- formatted sessions now use the label of "TLS SESSION" instead of "SSL SESSION".
+ formatted sessions now use the label of "TLS SESSION" instead of "SSL SESSION"
* Serialized TLS sessions are now encrypted using AES-256/GCM instead of a
CBC+HMAC construction.
diff --git a/src/cmd/tls_proxy.cpp b/src/cmd/tls_proxy.cpp
new file mode 100644
index 000000000..867e2280e
--- /dev/null
+++ b/src/cmd/tls_proxy.cpp
@@ -0,0 +1,592 @@
+/*
+* TLS Server Proxy
+* (C) 2014,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "apps.h"
+
+#if defined(BOTAN_HAS_TLS)
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <thread>
+
+#define _GLIBCXX_HAVE_GTHR_DEFAULT
+#include <boost/asio.hpp>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+
+#include <botan/tls_server.h>
+#include <botan/x509cert.h>
+#include <botan/pkcs8.h>
+#include <botan/auto_rng.h>
+
+#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
+ #include <botan/tls_session_manager_sqlite.h>
+#endif
+
+using boost::asio::ip::tcp;
+
+namespace Botan {
+
+namespace {
+
+void log_exception(const char* where, const std::exception& e)
+ {
+ std::cout << where << ' ' << e.what() << std::endl;
+ }
+
+void log_error(const char* where, const boost::system::error_code& error)
+ {
+ std::cout << where << ' ' << error.message() << std::endl;
+ }
+
+void log_binary_message(const char* where, const byte buf[], size_t buf_len)
+ {
+ //std::cout << where << ' ' << hex_encode(buf, buf_len) << std::endl;
+ }
+
+void log_text_message(const char* where, const byte buf[], size_t buf_len)
+ {
+ //const char* c = reinterpret_cast<const char*>(buf);
+ //std::cout << where << ' ' << std::string(c, c + buf_len) << std::endl;
+ }
+
+class tls_proxy_session : public boost::enable_shared_from_this<tls_proxy_session>
+ {
+ public:
+ enum { readbuf_size = 4 * 1024 };
+
+ typedef boost::shared_ptr<tls_proxy_session> pointer;
+
+ static pointer create(boost::asio::io_service& io,
+ TLS::Session_Manager& session_manager,
+ Credentials_Manager& credentials,
+ TLS::Policy& policy,
+ RandomNumberGenerator& rng,
+ tcp::resolver::iterator endpoints)
+ {
+ return pointer(
+ new tls_proxy_session(
+ io,
+ session_manager,
+ credentials,
+ policy,
+ rng,
+ endpoints)
+ );
+ }
+
+ tcp::socket& client_socket() { return m_client_socket; }
+
+ void start()
+ {
+ m_c2p.resize(readbuf_size);
+
+ client_read(boost::system::error_code(), 0); // start read loop
+ }
+
+ void stop() { m_client_socket.close(); }
+
+ private:
+ tls_proxy_session(boost::asio::io_service& io,
+ TLS::Session_Manager& session_manager,
+ Credentials_Manager& credentials,
+ TLS::Policy& policy,
+ RandomNumberGenerator& rng,
+ tcp::resolver::iterator endpoints) :
+ m_strand(io),
+ m_server_endpoints(endpoints),
+ m_client_socket(io),
+ m_server_socket(io),
+ m_tls(boost::bind(&tls_proxy_session::tls_proxy_write_to_client, this, _1, _2),
+ boost::bind(&tls_proxy_session::tls_client_write_to_proxy, this, _1, _2),
+ boost::bind(&tls_proxy_session::tls_alert_cb, this, _1, _2, _3),
+ boost::bind(&tls_proxy_session::tls_handshake_complete, this, _1),
+ session_manager,
+ credentials,
+ policy,
+ rng)
+ {
+ }
+
+ void client_read(const boost::system::error_code& error,
+ size_t bytes_transferred)
+ {
+ if(error)
+ {
+ log_error("Read failed", error);
+ stop();
+ return;
+ }
+
+ try
+ {
+ if(!m_tls.is_active())
+ log_binary_message("From client", &m_c2p[0], bytes_transferred);
+ m_tls.received_data(&m_c2p[0], bytes_transferred);
+ }
+ catch(std::exception& e)
+ {
+ log_exception("TLS connection failed", e);
+ stop();
+ return;
+ }
+
+ m_client_socket.async_read_some(
+ boost::asio::buffer(&m_c2p[0], m_c2p.size()),
+ m_strand.wrap(boost::bind(&tls_proxy_session::client_read, shared_from_this(),
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+ }
+
+ void handle_client_write_completion(const boost::system::error_code& error)
+ {
+ if(error)
+ {
+ log_error("Client write", error);
+ stop();
+ return;
+ }
+
+ m_p2c.clear();
+ tls_proxy_write_to_client(nullptr, 0); // initiate another write if needed
+ }
+
+ void handle_server_write_completion(const boost::system::error_code& error)
+ {
+ if(error)
+ {
+ log_error("Server write", error);
+ stop();
+ return;
+ }
+
+ m_p2s.clear();
+ tls_proxy_write_to_server(nullptr, 0); // initiate another write if needed
+ }
+
+ void tls_client_write_to_proxy(const byte buf[], size_t buf_len)
+ {
+ tls_proxy_write_to_server(buf, buf_len);
+ }
+
+ void tls_proxy_write_to_client(const byte buf[], size_t buf_len)
+ {
+ if(buf_len > 0)
+ m_p2c_pending.insert(m_p2c_pending.end(), buf, buf + buf_len);
+
+ // no write now active and we still have output pending
+ if(m_p2c.empty() && !m_p2c_pending.empty())
+ {
+ std::swap(m_p2c_pending, m_p2c);
+
+ //log_binary_message("To Client", &m_p2c[0], m_p2c.size());
+
+ boost::asio::async_write(
+ m_client_socket,
+ boost::asio::buffer(&m_p2c[0], m_p2c.size()),
+ m_strand.wrap(boost::bind(
+ &tls_proxy_session::handle_client_write_completion,
+ shared_from_this(),
+ boost::asio::placeholders::error)));
+ }
+ }
+
+ void tls_proxy_write_to_server(const byte buf[], size_t buf_len)
+ {
+ if(buf_len > 0)
+ m_p2s_pending.insert(m_p2s_pending.end(), buf, buf + buf_len);
+
+ // no write now active and we still have output pending
+ if(m_p2s.empty() && !m_p2s_pending.empty())
+ {
+ std::swap(m_p2s_pending, m_p2s);
+
+ log_text_message("To Server", &m_p2s[0], m_p2s.size());
+
+ boost::asio::async_write(
+ m_server_socket,
+ boost::asio::buffer(&m_p2s[0], m_p2s.size()),
+ m_strand.wrap(boost::bind(
+ &tls_proxy_session::handle_server_write_completion,
+ shared_from_this(),
+ boost::asio::placeholders::error)));
+ }
+ }
+
+ void server_read(const boost::system::error_code& error,
+ size_t bytes_transferred)
+ {
+ if(error)
+ {
+ log_error("Server read failed", error);
+ stop();
+ return;
+ }
+
+ try
+ {
+ if(bytes_transferred)
+ {
+ log_text_message("Server to client", &m_s2p[0], m_s2p.size());
+ log_binary_message("Server to client", &m_s2p[0], m_s2p.size());
+ m_tls.send(&m_s2p[0], bytes_transferred);
+ }
+ }
+ catch(std::exception& e)
+ {
+ log_exception("TLS connection failed", e);
+ stop();
+ return;
+ }
+
+ m_s2p.resize(readbuf_size);
+
+ m_server_socket.async_read_some(
+ boost::asio::buffer(&m_s2p[0], m_s2p.size()),
+ m_strand.wrap(boost::bind(&tls_proxy_session::server_read, shared_from_this(),
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+ }
+
+ bool tls_handshake_complete(const TLS::Session& session)
+ {
+ //std::cout << "Handshake from client complete\n";
+
+ m_hostname = session.server_info().hostname();
+
+ if(m_hostname != "")
+ std::cout << "Client requested hostname '" << m_hostname << "'\n";
+
+ async_connect(m_server_socket, m_server_endpoints,
+ [this](boost::system::error_code ec, tcp::resolver::iterator endpoint)
+ {
+ if(ec)
+ {
+ log_error("Server connection", ec);
+ return;
+ }
+ //std::cout << "Connected to " << endpoint->host_name() << ' '
+ //<< endpoint->service_name() << "\n";
+ tls_proxy_write_to_server(nullptr, 0);
+
+ server_read(boost::system::error_code(), 0); // start read loop
+ });
+ return true;
+ }
+
+ void tls_alert_cb(TLS::Alert alert, const byte[], size_t)
+ {
+ if(alert.type() == TLS::Alert::CLOSE_NOTIFY)
+ {
+ m_tls.close();
+ return;
+ }
+ else
+ std::cout << "Alert " << alert.type_string() << "\n";
+ }
+
+ boost::asio::io_service::strand m_strand;
+
+ tcp::resolver::iterator m_server_endpoints;
+
+ tcp::socket m_client_socket;
+ tcp::socket m_server_socket;
+
+ TLS::Server m_tls;
+ std::string m_hostname;
+
+ std::vector<byte> m_c2p;
+ std::vector<byte> m_p2c;
+ std::vector<byte> m_p2c_pending;
+
+ std::vector<byte> m_s2p;
+ std::vector<byte> m_p2s;
+ std::vector<byte> m_p2s_pending;
+ };
+
+class tls_proxy_server
+ {
+ public:
+ typedef tls_proxy_session session;
+
+ tls_proxy_server(boost::asio::io_service& io, unsigned short port,
+ tcp::resolver::iterator endpoints,
+ Credentials_Manager& creds,
+ TLS::Policy& policy,
+ TLS::Session_Manager& session_mgr,
+ RandomNumberGenerator& rng) :
+ m_acceptor(io, tcp::endpoint(tcp::v4(), port)),
+ m_server_endpoints(endpoints),
+ m_creds(creds),
+ m_policy(policy),
+ m_session_manager(session_mgr),
+ m_rng(rng)
+ {
+ session::pointer new_session = make_session();
+
+ m_acceptor.async_accept(
+ new_session->client_socket(),
+ boost::bind(
+ &tls_proxy_server::handle_accept,
+ this,
+ new_session,
+ boost::asio::placeholders::error)
+ );
+ }
+
+ private:
+ session::pointer make_session()
+ {
+ return session::create(
+ m_acceptor.get_io_service(),
+ m_session_manager,
+ m_creds,
+ m_policy,
+ m_rng,
+ m_server_endpoints
+ );
+ }
+
+ void handle_accept(session::pointer new_session,
+ const boost::system::error_code& error)
+ {
+ if (!error)
+ {
+ new_session->start();
+
+ new_session = make_session();
+
+ m_acceptor.async_accept(
+ new_session->client_socket(),
+ boost::bind(
+ &tls_proxy_server::handle_accept,
+ this,
+ new_session,
+ boost::asio::placeholders::error)
+ );
+ }
+ }
+
+ tcp::acceptor m_acceptor;
+ tcp::resolver::iterator m_server_endpoints;
+
+ Credentials_Manager& m_creds;
+ TLS::Policy& m_policy;
+ TLS::Session_Manager& m_session_manager;
+ RandomNumberGenerator& m_rng;
+ };
+
+size_t choose_thread_count()
+ {
+ size_t result = std::thread::hardware_concurrency();
+
+ if(result)
+ return result;
+
+ return 2;
+ }
+
+class Proxy_Credentials_Manager : public Credentials_Manager
+ {
+ public:
+ Proxy_Credentials_Manager(RandomNumberGenerator& rng,
+ const std::string& server_crt,
+ const std::string& server_key)
+ {
+ try
+ {
+ Certificate_Info cert;
+
+
+ try
+ {
+ cert.key.reset(PKCS8::load_key(server_key, rng));
+ }
+ catch(std::exception& e)
+ {
+ log_exception("Loading server key", e);
+ throw; // fatal
+ }
+
+ try
+ {
+ DataSource_Stream in(server_crt);
+ while(!in.end_of_data())
+ cert.certs.push_back(X509_Certificate(in));
+ }
+ catch(std::exception& e)
+ {
+ log_exception("Loading certs", e);
+ }
+
+ // TODO: attempt to validate chain ourselves
+
+ m_creds.push_back(cert);
+ }
+ catch(std::exception& e)
+ {
+ log_exception("Loading server key", e);
+ throw; // fatal
+ }
+
+ try
+ {
+ // TODO: make path configurable
+ std::shared_ptr<Certificate_Store> cs(new Certificate_Store_In_Memory("/usr/share/ca-certificates"));
+ m_certstores.push_back(cs);
+ }
+ catch(std::exception& e)
+ {
+ log_exception("Loading CA certs", e);
+ //throw; // not fatal
+ }
+ }
+
+ std::vector<Botan::Certificate_Store*>
+ trusted_certificate_authorities(const std::string& type,
+ const std::string& /*hostname*/)
+ {
+ std::vector<Botan::Certificate_Store*> v;
+
+ // don't ask for client certs
+ if(type == "tls-server")
+ return v;
+
+ for(auto&& cs : m_certstores)
+ v.push_back(cs.get());
+
+ return v;
+ }
+
+ void verify_certificate_chain(
+ const std::string& type,
+ const std::string& purported_hostname,
+ const std::vector<X509_Certificate>& cert_chain)
+ {
+ try
+ {
+ Credentials_Manager::verify_certificate_chain(type,
+ purported_hostname,
+ cert_chain);
+ }
+ catch(std::exception& e)
+ {
+ std::cout << "Certificate validation failure: " << e.what() << "\n";
+ throw;
+ }
+ }
+
+ std::vector<X509_Certificate> cert_chain(
+ const std::vector<std::string>& algos,
+ const std::string& type,
+ const std::string& hostname)
+ {
+ for(auto&& i : m_creds)
+ {
+ if(std::find(algos.begin(), algos.end(), i.key->algo_name()) == algos.end())
+ continue;
+
+ if(hostname != "" && !i.certs[0].matches_dns_name(hostname))
+ continue;
+
+ return i.certs;
+ }
+
+ return std::vector<X509_Certificate>();
+ }
+
+ Private_Key* private_key_for(const X509_Certificate& cert,
+ const std::string& /*type*/,
+ const std::string& /*context*/)
+ {
+ for(auto&& i : m_creds)
+ {
+ if(cert == i.certs[0])
+ return i.key.get();
+ }
+
+ return nullptr;
+ }
+
+ private:
+ struct Certificate_Info
+ {
+ std::vector<X509_Certificate> certs;
+ std::shared_ptr<Private_Key> key;
+ };
+
+ std::vector<Certificate_Info> m_creds;
+ std::vector<std::shared_ptr<Certificate_Store>> m_certstores;
+ };
+
+int tls_proxy(int argc, char* argv[])
+ {
+ if(argc != 6)
+ {
+ std::cout << "Usage: " << argv[0] << " listen_port target_host target_port server_cert server_key\n";
+ return 1;
+ }
+
+ const size_t listen_port = to_u32bit(argv[1]);
+ const std::string target = argv[2];
+ const std::string target_port = argv[3];
+
+ const std::string server_crt = argv[4];
+ const std::string server_key = argv[5];
+
+ const size_t num_threads = choose_thread_count(); // make configurable
+
+ AutoSeeded_RNG rng;
+ Proxy_Credentials_Manager creds(rng, server_crt, server_key);
+
+ TLS::Policy policy; // TODO: Read policy from text file
+
+ try
+ {
+ boost::asio::io_service io;
+
+ tcp::resolver resolver(io);
+ auto server_endpoint_iterator = resolver.resolve({ target, target_port });
+
+#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
+ // Todo: make configurable
+ const std::string sessions_passphrase = "correct horse battery staple";
+ const std::string sessions_db = "sessions.db";
+ TLS::Session_Manager_SQLite sessions(sessions_passphrase, rng, sessions_db);
+#else
+ TLS::Session_Manager_In_Memory sessions(rng);
+#endif
+
+ tls_proxy_server server(io, listen_port, server_endpoint_iterator, creds, policy, sessions, rng);
+
+ std::vector<std::shared_ptr<std::thread>> threads;
+
+ for(size_t i = 2; i <= num_threads; ++i)
+ threads.push_back(std::make_shared<std::thread>([&io]() { io.run(); }));
+
+ io.run();
+
+ for (size_t i = 0; i < threads.size(); ++i)
+ threads[i]->join();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << e.what() << std::endl;
+ }
+
+ return 0;
+ }
+
+}
+
+}
+
+REGISTER_APP(tls_proxy);
+
+#endif
diff --git a/src/cmd/tls_server_asio.cpp b/src/cmd/tls_server_asio.cpp
deleted file mode 100644
index 9d31107bb..000000000
--- a/src/cmd/tls_server_asio.cpp
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
-* (C) 2014 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include "apps.h"
-
-#if defined(BOTAN_HAS_TLS)
-#include <iostream>
-#include <string>
-#include <vector>
-#include <thread>
-#define _GLIBCXX_HAVE_GTHR_DEFAULT
-#include <boost/asio.hpp>
-#include <boost/bind.hpp>
-//#include <boost/thread.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/enable_shared_from_this.hpp>
-
-#include <botan/tls_server.h>
-#include <botan/x509cert.h>
-#include <botan/pkcs8.h>
-#include <botan/auto_rng.h>
-
-#include "credentials.h"
-
-using Botan::byte;
-using boost::asio::ip::tcp;
-
-namespace {
-
-class tls_server_session : public boost::enable_shared_from_this<tls_server_session>
- {
- public:
- typedef boost::shared_ptr<tls_server_session> pointer;
-
- static pointer create(boost::asio::io_service& io_service,
- Botan::TLS::Session_Manager& session_manager,
- Botan::Credentials_Manager& credentials,
- Botan::TLS::Policy& policy,
- Botan::RandomNumberGenerator& rng)
- {
- return pointer(
- new tls_server_session(
- io_service,
- session_manager,
- credentials,
- policy,
- rng)
- );
- }
-
- tcp::socket& socket() { return m_socket; }
-
- void start()
- {
- m_socket.async_read_some(
- boost::asio::buffer(m_read_buf, sizeof(m_read_buf)),
- m_strand.wrap(
- boost::bind(&tls_server_session::handle_read, shared_from_this(),
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred)));
- }
-
- void stop() { m_socket.close(); }
-
- private:
- tls_server_session(boost::asio::io_service& io_service,
- Botan::TLS::Session_Manager& session_manager,
- Botan::Credentials_Manager& credentials,
- Botan::TLS::Policy& policy,
- Botan::RandomNumberGenerator& rng) :
- m_strand(io_service),
- m_socket(io_service),
- m_tls(boost::bind(&tls_server_session::tls_output_wanted, this, _1, _2),
- boost::bind(&tls_server_session::tls_data_recv, this, _1, _2),
- boost::bind(&tls_server_session::tls_alert_cb, this, _1, _2, _3),
- boost::bind(&tls_server_session::tls_handshake_complete, this, _1),
- session_manager,
- credentials,
- policy,
- rng)
- {
- }
-
- void handle_read(const boost::system::error_code& error,
- size_t bytes_transferred)
- {
- if(!error)
- {
- try
- {
- m_tls.received_data(m_read_buf, bytes_transferred);
- }
- catch(std::exception& e)
- {
- std::cout << "Read failed " << e.what() << "\n";
- stop();
- return;
- }
-
- m_socket.async_read_some(
- boost::asio::buffer(m_read_buf, sizeof(m_read_buf)),
- m_strand.wrap(boost::bind(&tls_server_session::handle_read, shared_from_this(),
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred)));
- }
- else
- {
- stop();
- }
- }
-
- void handle_write(const boost::system::error_code& error)
- {
- if(!error)
- {
- m_write_buf.clear();
-
- // initiate another write if needed
- tls_output_wanted(nullptr, 0);
- }
- else
- {
- stop();
- }
- }
-
- void tls_output_wanted(const byte buf[], size_t buf_len)
- {
- if(buf_len > 0)
- m_outbox.insert(m_outbox.end(), buf, buf + buf_len);
-
- // no write pending and have output pending
- if(m_write_buf.empty() && !m_outbox.empty())
- {
- std::swap(m_outbox, m_write_buf);
-
- boost::asio::async_write(m_socket,
- boost::asio::buffer(&m_write_buf[0], m_write_buf.size()),
- m_strand.wrap(
- boost::bind(&tls_server_session::handle_write,
- shared_from_this(),
- boost::asio::placeholders::error)));
- }
- }
-
- void tls_alert_cb(Botan::TLS::Alert alert, const byte[], size_t)
- {
- if(alert.type() == Botan::TLS::Alert::CLOSE_NOTIFY)
- {
- m_tls.close();
- return;
- }
- }
-
- void tls_data_recv(const byte buf[], size_t buf_len)
- {
- m_client_data.insert(m_client_data.end(), buf, buf + buf_len);
-
- if(ready_to_respond())
- write_response();
- }
-
- bool ready_to_respond()
- {
- return true; // parse headers?
- }
-
- void write_response()
- {
- std::string out;
- out += "\r\n";
- out += "HTTP/1.0 200 OK\r\n";
- out += "Server: Botan ASIO test server\r\n";
- if(m_hostname != "")
- out += "Host: " + m_hostname + "\r\n";
- out += "Content-Type: text/html\r\n";
- out += "\r\n";
- out += "<html><body>Greets. You said: ";
- out += std::string(reinterpret_cast<const char*>(&m_client_data[0]),
- m_client_data.size());
- out += "</body></html>\r\n\r\n";
-
- m_tls.send(out);
- m_tls.close();
- }
-
- bool tls_handshake_complete(const Botan::TLS::Session& session)
- {
- m_hostname = session.server_info().hostname();
- return true;
- }
-
- boost::asio::io_service::strand m_strand; // serialization
-
- tcp::socket m_socket;
- Botan::TLS::Server m_tls;
- std::string m_hostname;
-
- unsigned char m_read_buf[1024];
-
- // used to hold the data currently being written by the system
- std::vector<byte> m_write_buf;
-
- // used to hold data queued for writing
- std::vector<byte> m_outbox;
-
- std::vector<byte> m_client_data;
- };
-
-class asio_tls_server
- {
- public:
- typedef tls_server_session session;
-
- asio_tls_server(boost::asio::io_service& io_service, unsigned short port) :
- m_acceptor(io_service, tcp::endpoint(tcp::v4(), port)),
- m_session_manager(m_rng),
- m_creds(m_rng)
- {
- session::pointer new_session = make_session();
-
- m_acceptor.async_accept(
- new_session->socket(),
- boost::bind(
- &asio_tls_server::handle_accept,
- this,
- new_session,
- boost::asio::placeholders::error)
- );
- }
-
- private:
- session::pointer make_session()
- {
- return session::create(
- m_acceptor.get_io_service(),
- m_session_manager,
- m_creds,
- m_policy,
- m_rng
- );
- }
-
- void handle_accept(session::pointer new_session,
- const boost::system::error_code& error)
- {
- if (!error)
- {
- new_session->start();
-
- new_session = make_session();
-
- m_acceptor.async_accept(
- new_session->socket(),
- boost::bind(
- &asio_tls_server::handle_accept,
- this,
- new_session,
- boost::asio::placeholders::error)
- );
- }
- }
-
- tcp::acceptor m_acceptor;
-
- Botan::AutoSeeded_RNG m_rng;
- Botan::TLS::Session_Manager_In_Memory m_session_manager;
- Botan::TLS::Policy m_policy;
- Credentials_Manager_Simple m_creds;
- };
-
-size_t choose_thread_count()
- {
- size_t result = std::thread::hardware_concurrency();
-
- if(result)
- return result;
-
- return 2;
- }
-
-int tls_server_asio(int argc, char* argv[])
- {
- try
- {
- boost::asio::io_service io_service;
-
- const unsigned short port = 4434;
- asio_tls_server server(io_service, port);
-
- size_t num_threads = choose_thread_count();
- if(argc == 2)
- std::istringstream(argv[1]) >> num_threads;
-
- std::cout << "Using " << num_threads << " threads\n";
-
- std::vector<boost::shared_ptr<std::thread> > threads;
-
- for(size_t i = 0; i != num_threads; ++i)
- {
- boost::shared_ptr<std::thread> thread(
- new std::thread(
- boost::bind(&boost::asio::io_service::run, &io_service)));
- threads.push_back(thread);
- }
-
- // Wait for all threads in the pool to exit.
- for (size_t i = 0; i < threads.size(); ++i)
- threads[i]->join();
- }
- catch (std::exception& e)
- {
- std::cerr << e.what() << std::endl;
- }
-
- return 0;
- }
-
-}
-
-REGISTER_APP(tls_server_asio);
-
-#endif