From 918685c1c09de1e3cd14c41bb8cc8b89a177ccd2 Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sun, 5 Apr 2020 12:03:52 +0200 Subject: Different certificates for different hosts --- TODO | 3 +++ config.cpp | 2 +- config.h | 2 +- http.cpp | 36 +++++++++++++++++++++------------- https.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++---------------- https.h | 2 ++ server.h | 2 ++ 7 files changed, 80 insertions(+), 33 deletions(-) diff --git a/TODO b/TODO index 1d083ca..5ec5b0e 100644 --- a/TODO +++ b/TODO @@ -2,3 +2,6 @@ Certbot: https://certbot.eff.org/lets-encrypt/debianbuster-other Webbox Debian 10 alternative hosts www, lists, ... + +drop privileges: www-data,www-data, ...? +Speed up DocRoot, use string_view diff --git a/config.cpp b/config.cpp index 4e33dfc..6050768 100644 --- a/config.cpp +++ b/config.cpp @@ -182,7 +182,7 @@ void Config::dump() const std::cout << "=============================================" << std::endl; } -std::string Config::DocRoot(const Socket& socket, const std::string& requested_host, const std::string& requested_path) +std::string Config::DocRoot(const Socket& socket, const std::string& requested_host, const std::string& requested_path) const { // TODO: speed this up std::string host{requested_host}; diff --git a/config.h b/config.h index 0f5ec78..1c938c0 100644 --- a/config.h +++ b/config.h @@ -71,7 +71,7 @@ class Config const std::vector& Sockets() const; /// param[in] requested_host e.g. www.domain.com:8080 or www.domain.com - std::string DocRoot(const Socket& socket, const std::string& requested_host, const std::string& requested_path); + std::string DocRoot(const Socket& socket, const std::string& requested_host, const std::string& requested_path) const; void dump() const; }; diff --git a/http.cpp b/http.cpp index eb4dc8c..2203ffe 100644 --- a/http.cpp +++ b/http.cpp @@ -97,7 +97,8 @@ template< class Send> void handle_request( - beast::string_view doc_root, + const Config& config, + const Socket& socket, http::request>&& req, Send&& send) { @@ -152,8 +153,9 @@ handle_request( return send(bad_request("Illegal request-target")); // Build the path to the requested file - std::string path = path_cat(doc_root, req.target()); - std::cout << "DEBUG: " << req["host"] << "|" << req.target() << std::endl; + std::string host{req["host"]}; // TODO: just use string_view + std::string target{req.target()}; + std::string path = path_cat(config.DocRoot(socket, host, target), req.target()); if(req.target().back() == '/') path.append("index.html"); @@ -247,7 +249,8 @@ class session : public std::enable_shared_from_this beast::tcp_stream stream_; beast::flat_buffer buffer_; - std::shared_ptr doc_root_; + const Config& m_config; + const Socket& m_socket; http::request req_; std::shared_ptr res_; send_lambda lambda_; @@ -256,9 +259,11 @@ public: // Take ownership of the stream session( tcp::socket&& socket, - std::shared_ptr const& doc_root) + const Config& config, + const Socket& config_socket) : stream_(std::move(socket)) - , doc_root_(doc_root) + , m_config(config) + , m_socket(config_socket) , lambda_(*this) { } @@ -309,7 +314,7 @@ public: return fail(ec, "read"); // Send the response - handle_request(*doc_root_, std::move(req_), lambda_); + handle_request(m_config, m_socket , std::move(req_), lambda_); } void @@ -355,16 +360,19 @@ class listener : public std::enable_shared_from_this { net::io_context& ioc_; tcp::acceptor acceptor_; - std::shared_ptr doc_root_; + const Config& m_config; + const Socket& m_socket; public: listener( net::io_context& ioc, tcp::endpoint endpoint, - std::shared_ptr const& doc_root) + const Config& config, + const Socket& socket) : ioc_(ioc) , acceptor_(net::make_strand(ioc)) - , doc_root_(doc_root) + , m_config(config) + , m_socket(socket) { beast::error_code ec; @@ -433,7 +441,8 @@ private: // Create the session and run it std::make_shared( std::move(socket), - doc_root_)->run(); + m_config, + m_socket)->run(); } // Accept another connection @@ -457,16 +466,15 @@ namespace HTTP { int Server::start() { - // TODO: Config auto const address = net::ip::make_address(m_socket.address); auto const port = static_cast(std::atoi(m_socket.port.data())); - auto const doc_root = std::make_shared(m_config.Sites()[0].paths[0].params.at("target")); // Create and launch a listening port std::make_shared( m_ioc, tcp::endpoint{address, port}, - doc_root)->run(); + m_config, + m_socket)->run(); return EXIT_SUCCESS; } diff --git a/https.cpp b/https.cpp index b4e77f9..9d0784e 100644 --- a/https.cpp +++ b/https.cpp @@ -8,6 +8,7 @@ #include "server_certificate.h" +#include #include #include #include @@ -104,7 +105,8 @@ template< class Send> void handle_request( - beast::string_view doc_root, + const Config& config, + const Socket& socket, http::request>&& req, Send&& send) { @@ -159,7 +161,9 @@ handle_request( return send(bad_request("Illegal request-target")); // Build the path to the requested file - std::string path = path_cat(doc_root, req.target()); + std::string host{req["host"]}; // TODO: just use string_view + std::string target{req.target()}; + std::string path = path_cat(config.DocRoot(socket, host, target), req.target()); if(req.target().back() == '/') path.append("index.html"); @@ -273,7 +277,8 @@ class session : public std::enable_shared_from_this beast::ssl_stream stream_; beast::flat_buffer buffer_; - std::shared_ptr doc_root_; + const Config& m_config; + const Socket& m_socket; http::request req_; std::shared_ptr res_; send_lambda lambda_; @@ -284,9 +289,11 @@ public: session( tcp::socket&& socket, ssl::context& ctx, - std::shared_ptr const& doc_root) + const Config& config, + const Socket& config_socket) : stream_(std::move(socket), ctx) - , doc_root_(doc_root) + , m_config(config) + , m_socket(config_socket) , lambda_(*this) { } @@ -296,9 +303,7 @@ public: run() { // We need to be executing within a strand to perform async operations - // on the I/O objects in this session. Although not strictly necessary - // for single-threaded contexts, this example code is written to be - // thread-safe by default. + // on the I/O objects in this session. net::dispatch( stream_.get_executor(), beast::bind_front_handler( @@ -362,7 +367,7 @@ public: return fail(ec, "read"); // Send the response - handle_request(*doc_root_, std::move(req_), lambda_); + handle_request(m_config, m_socket, std::move(req_), lambda_); } void @@ -421,18 +426,21 @@ class listener : public std::enable_shared_from_this net::io_context& ioc_; ssl::context& ctx_; tcp::acceptor acceptor_; - std::shared_ptr doc_root_; + const Config& m_config; + const Socket& m_socket; public: listener( net::io_context& ioc, ssl::context& ctx, tcp::endpoint endpoint, - std::shared_ptr const& doc_root) + const Config& config, + const Socket& socket) : ioc_(ioc) , ctx_(ctx) , acceptor_(ioc) - , doc_root_(doc_root) + , m_config(config) + , m_socket(socket) { beast::error_code ec; @@ -502,7 +510,8 @@ private: std::make_shared( std::move(socket), ctx_, - doc_root_)->run(); + m_config, + m_socket)->run(); } // Accept another connection @@ -515,10 +524,34 @@ private: namespace HTTPS { +int servername_callback(SSL *s, int *al, void *arg) +{ + int type {SSL_get_servername_type(s)}; + std::string server_name {SSL_get_servername(s, type)}; + + Server* server = (Server*)arg; + if (server_name == "lists.antcom.de"s) { + SSL_set_SSL_CTX(s, server->m_ctx.native_handle()); + } else { + SSL_set_SSL_CTX(s, server->m_ctx2.native_handle()); + } + return SSL_TLSEXT_ERR_OK; +} + Server::Server(Config& config, boost::asio::io_context& ioc, const Socket& socket): ::Server(config, ioc), m_socket(socket) { - // This holds the self-signed certificate used by the server + for (const auto& site: socket.serve_sites) { + std::cout << "Creating SSL context/cert for site " << site << std::endl; + } + load_server_certificate(m_ctx, m_socket.cert_path, m_socket.key_path); + load_server_certificate(m_ctx2, "/home/ernie/code/webserver/cert.pem", "/home/ernie/code/webserver/key.pem"); + + SSL_CTX_set_tlsext_servername_callback(m_ctx.native_handle(), servername_callback); + SSL_CTX_set_tlsext_servername_arg(m_ctx.native_handle(), this); + + SSL_CTX_set_tlsext_servername_callback(m_ctx2.native_handle(), servername_callback); + SSL_CTX_set_tlsext_servername_arg(m_ctx2.native_handle(), this); } Server::~Server() @@ -527,17 +560,16 @@ Server::~Server() int Server::start() { - // TODO: Config auto const address = net::ip::make_address(m_socket.address); auto const port = static_cast(std::atoi(m_socket.port.data())); - auto const doc_root = std::make_shared(m_config.Sites()[0].paths[0].params.at("target")); // Create and launch a listening port std::make_shared( m_ioc, m_ctx, tcp::endpoint{address, port}, - doc_root)->run(); + m_config, + m_socket)->run(); return EXIT_SUCCESS; } diff --git a/https.h b/https.h index e137463..13a67a7 100644 --- a/https.h +++ b/https.h @@ -15,7 +15,9 @@ namespace HTTPS { class Server: public ::Server { // The SSL context is required, and holds certificates +public: ssl::context m_ctx{ssl::context::tlsv13}; + ssl::context m_ctx2{ssl::context::tlsv13}; const Socket& m_socket; public: diff --git a/server.h b/server.h index 0dcf3dd..5e5343f 100644 --- a/server.h +++ b/server.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "config.h" using namespace std::string_literals; -- cgit v1.2.3