From edb8e44b5a12776a6b5ce4bb5316e4c8acdd858a Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Sat, 7 Jan 2023 12:09:14 +0100 Subject: Fix TLS certificate verification --- https.cpp | 17 +++++++++-- tests/test-webserver.cpp | 78 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 79 insertions(+), 16 deletions(-) diff --git a/https.cpp b/https.cpp index 10f76e0..523acb5 100644 --- a/https.cpp +++ b/https.cpp @@ -476,7 +476,7 @@ void load_server_certificate(boost::asio::ssl::context& ctx, const fs::path& cer The certificate was generated from CMD.EXE on Windows 10 using: winpty openssl dhparam -out dh.pem 2048 - winpty openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 10000 -out cert.pem -subj "//C=US\ST=CA\L=Los Angeles\O=Beast\CN=www.example.com" + winpty openssl req -newkey rsa:4096 -sha256 -nodes -keyout key.pem -x509 -days 10000 -out cert.pem -subj "//C=DE\ST=BY\L=Munich\O=Reichwein\CN=reichwein.it" */ std::string const dh = @@ -531,7 +531,7 @@ void load_server_certificate(boost::asio::ssl::context& ctx, const fs::path& cer std::string key; if (key_path == "") { - // generate dummy self signed certificate. Will be replaced by real + // use dummy self signed key. Will be replaced by real // certificate if configured upon respective session key = "-----BEGIN PRIVATE KEY-----\n" @@ -581,6 +581,15 @@ int ServerNameError(SSL *s, HTTPS::Server::ctx_type& ctx_map) return SSL_CLIENT_HELLO_SUCCESS; // OK for now } +std::string unbracketed(const std::string& s) +{ + if (s.size() >= 2 && s.front() == '[' && s.back() == ']') { + return s.substr(1, s.size() - 2); + } else { + return s; + } +} + int servername_callback(SSL *s, int *al, void *arg) { HTTPS::Server::ctx_type& ctx_map = *(HTTPS::Server::ctx_type*)arg; @@ -618,6 +627,8 @@ int servername_callback(SSL *s, int *al, void *arg) if (server_name.size() >= 5 && server_name[0] == '\0') server_name = server_name.substr(5); + server_name = unbracketed(server_name); + auto it {ctx_map.find(server_name)}; std::shared_ptr ctx{}; if (it != ctx_map.end()) { @@ -668,7 +679,7 @@ void Server::load_certificates() for (const auto& host: site.second.hosts) { std::cout << " Adding Host " << host << std::endl; - m_ctx.emplace(host, ctx); + m_ctx.emplace(unbracketed(host), ctx); } } } diff --git a/tests/test-webserver.cpp b/tests/test-webserver.cpp index feb4f2a..53aa9cc 100644 --- a/tests/test-webserver.cpp +++ b/tests/test-webserver.cpp @@ -52,10 +52,13 @@ namespace pt = boost::property_tree; using namespace boost::unit_test; using namespace Reichwein; +const fs::path testConfigFilename{"./webserver.conf"}; +const fs::path testCertFilename{"./testchain.pem"}; +const fs::path testKeyFilename{"./testkey.pem"}; + class WebserverProcess { public: - const fs::path testConfigFilename{"./webserver.conf"}; WebserverProcess(): m_pid{} { File::setFile(testConfigFilename, R"CONFIG( @@ -74,8 +77,8 @@ public: static-files . - ../fullchain.pem - ../privkey.pem + testchain.pem + testkey.pem @@ -105,9 +108,57 @@ public: - )CONFIG"); + // test self signed certificate + File::setFile(testCertFilename, R"(-----BEGIN CERTIFICATE----- +MIIC4zCCAcugAwIBAgIUeS9y+EsFWxf+foEx6SJ/R56rmX8wDQYJKoZIhvcNAQEL +BQAwADAgFw0yMzAxMDYxNzIwNTFaGA8yMDUwMDUyNDE3MjA1MVowADCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALiZSICAcXng9j7zAb873U4TpuzvRVfh +xS3gEhxqNPs6+ZQ43nAxDSdafzfGxpTkElTt/REj4oEOLw+QWI/jfbe4gDRDzf6V +ij0fVuzp02JtJSS+dNrLv17NufBydOyD8oDrPehVrPlrZQhhkYMvLHAim+wikT2O +s0es2R+avixxAZvx5EYgHba9T7R/pC/lA4BI3lEbVKjDA83hZvjPH1YdK+RYQS2g +Jygdhe8qOSswXIwFAF3MMBpwRD3mz+vAJZP3lpBGsn+asO6Xd/5cjC8msgomS8Ji +c9DMMNlrE1WU73wVG9n0OJcke2XEtzARVKJLlBPsug4oxDev6O4GakkCAwEAAaNT +MFEwHQYDVR0OBBYEFE4i7Gtyn30qpIkH6f0/wuFA45pjMB8GA1UdIwQYMBaAFE4i +7Gtyn30qpIkH6f0/wuFA45pjMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAIlGv4b2yLmTOrXOPNst2y3J+GiRvuMKoAfDt5KLxUhbCmPgJzGDWn0l +60xXBX/t2uo3dQa9yAIW64RqhEQX7uja/7B3PmJZlgF7+owvT8OZA4+UN1lLUvY4 +V7mUzuKuqo5jcX8EmZnHrJ4TGZ0dXbT1hAUgqIjnDChjWyvs4B9zZL5FTisPUic7 +MU+FcpKJ5M6iJ150d9hzLiwmJyPLkW5Grq0Jh22njUQwWW2vIMn4cA3CyS64+oi2 +DNnDgde3mYxXL8Oki7CbeCTpmUXcBHmQtWOvKZPCsOzMF4moTLC4DdElvOpwKCAK +ABd6rubkarwvDV7wEo1eSuAHPZ/KhGo= +-----END CERTIFICATE----- +)"); + File::setFile(testKeyFilename, R"(-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC4mUiAgHF54PY+ +8wG/O91OE6bs70VX4cUt4BIcajT7OvmUON5wMQ0nWn83xsaU5BJU7f0RI+KBDi8P +kFiP4323uIA0Q83+lYo9H1bs6dNibSUkvnTay79ezbnwcnTsg/KA6z3oVaz5a2UI +YZGDLyxwIpvsIpE9jrNHrNkfmr4scQGb8eRGIB22vU+0f6Qv5QOASN5RG1SowwPN +4Wb4zx9WHSvkWEEtoCcoHYXvKjkrMFyMBQBdzDAacEQ95s/rwCWT95aQRrJ/mrDu +l3f+XIwvJrIKJkvCYnPQzDDZaxNVlO98FRvZ9DiXJHtlxLcwEVSiS5QT7LoOKMQ3 +r+juBmpJAgMBAAECggEACjs5suCbmYAb2d2VZlRitdP+Q6HX37D0YTBrBI7o6JdK +U7oqrwBy/JBGHpDqewBgmTs3FGr/H/zJpDTRickXs9X6qhrreQ2wA6b/5gHoPMt0 +nHKfbqyOCuq/YGmxnBXMnDNdoynTfGAE0af5vRIBZiYu6vG4B9fHzURR5O/qVDNn +WqJ+2Y8AAf4mJDCBEvJz2RaZwSq788i/d8oTSeCk93TDF+GHhUq6ymkORACj76ws +8ohfoNQIG1VhdcTK2GOQjqctEFUm54t9N1nxD6VavMu5DlSSVsPTDbYuE5U4cy3T +ThDtoYJgwz5KRflklwl3xoDJVx3B5wMUaqviRp6l0QKBgQC6MPG+EV2drsHwG0Wg +gnP4uCSuFAfWBlHAQyZv5PMQBNfM8YjyMyL+O7cggGNJSOZr/X30EqoBe+LXrL3X +Gtix8F1Ed0fbAarAgxIwq8MktzmastDq4XS+zwYPZ7UTbmbqvT3VYPga4Sh90fyY +nPJpqZvhvGzQX22yeHS7vTSQOQKBgQD9z36EIYMuLl0HJK6gfjGHsy/Rx7bw1TmP +aHmuF8Ra7rpDSOym0ImKWTOLEoLlQUsMz/FuVLCGP/ACjMFKsqh3Zy/0hVJOMDMR +Z+ODT28Hcz4AMcTYDvcTYd70HhhZL+/eFCVk8Nk164saMuhifAkOgvwfaYs0m3ue +S9jxlZKKkQKBgHgBzf6k8MMOfaAF4/XVv2wDPFkbPgW74vtaDK84UVX02ScWUx9Q +yHA3Cwye09/LZgEazREA6qS0NfyvMVkwy5S9CVB01VKam3UjxhiqzMegdTd5o+CQ +WpAVnaFWRcb1dM4+FVmv+5pPn6qhKv8uwaxLDtcLfNM9ftX2f77176g5AoGADWtQ +DBpdfi6TWpJU7UVexwbxS00c3gTYAz4J2OuGxSwECxSq9nLmIrtunza+VvKpziac +ZDH0F1UAEpJwkct6Xr3E6k+2N04TFSOCAupLO4CbUZVQDABWjd7J0+xXaze+neZA +x+J4CYLHmv4ADVzzeaHxRJPm+UQTOB5YfQVkdxECgYBv3QuUMiBGKWgeheP4nAFU +SVgqGBQwAtqb5DR1YVJ4LFPt+jyrQMby6mqSlzENYcidSP3Ogn22CvST+bAjbf6D +D/ae1zeOHBls00ILHANv1Z/hXcEkiKnZdeP6O43xBfCS+Lps5daXgUbC0kw2R09S +VZTqPHmb+db0rFA3XlAg2A== +-----END PRIVATE KEY----- +)"); start(); } @@ -115,6 +166,8 @@ public: { stop(); fs::remove(testConfigFilename); + fs::remove(testCertFilename); + fs::remove(testKeyFilename); } void start() @@ -259,7 +312,7 @@ std::pair HTTP(const std::string& target, bool ipv6 = t void load_root_certificates(boost::asio::ssl::context& ctx) { - std::string cert_chain{File::getFile("../cert.pem")}; + std::string cert_chain{File::getFile(testCertFilename)}; ctx.add_certificate_authority(boost::asio::buffer(cert_chain.data(), cert_chain.size())); } @@ -357,27 +410,26 @@ public: BOOST_DATA_TEST_CASE_F(Fixture, http_get, data::make({false, true}) * data::make({false, true}) * data::make({false, true}) * data::make({boost::beast::http::verb::head, boost::beast::http::verb::get}), ipv6, http11, https, method) { - std::cout << "DEBUG: " << ipv6 << " " << http11 << " " << https << " " << method << std::endl; WebserverProcess serverProcess; BOOST_REQUIRE(serverProcess.isRunning()); std::pair response{https ? HTTPS("/webserver.conf", ipv6, http11, method) : HTTP("/webserver.conf", ipv6, http11, method)}; BOOST_REQUIRE(serverProcess.isRunning()); - BOOST_REQUIRE_EQUAL(response.first, fmt::format("HTTP/{} 200 OK\r\nServer: Reichwein.IT Webserver " VERSION "\r\nContent-Type: application/text\r\nContent-Length: {}\r\n\r\n", http11 ? "1.1" : "1.0", method == boost::beast::http::verb::head ? 0 : 1021)); - BOOST_REQUIRE_EQUAL(response.second, method == boost::beast::http::verb::head ? ""s : File::getFile(serverProcess.testConfigFilename)); -#if 0 + std::string::size_type size{File::getFile(testConfigFilename).size()}; + BOOST_CHECK_GT(size, 0); + BOOST_REQUIRE_EQUAL(response.first, fmt::format("HTTP/{} 200 OK\r\nServer: Reichwein.IT Webserver " VERSION "\r\nContent-Type: application/text\r\nContent-Length: {}\r\n\r\n", http11 ? "1.1" : "1.0", method == boost::beast::http::verb::head ? 0 : size)); + BOOST_REQUIRE_EQUAL(response.second, method == boost::beast::http::verb::head ? ""s : File::getFile(testConfigFilename)); + for (int i = 0; i < 10; i++) { std::pair response{https ? HTTPS("/webserver.conf", ipv6, http11, method) : HTTP("/webserver.conf", ipv6, http11, method)}; BOOST_REQUIRE(serverProcess.isRunning()); - BOOST_REQUIRE_EQUAL(response.first, fmt::format("HTTP/{} 200 OK\r\nServer: Reichwein.IT Webserver " VERSION "\r\nContent-Type: application/text\r\nContent-Length: {}\r\n\r\n", http11 ? "1.1" : "1.0", method == boost::beast::http::verb::head ? 0 : 1021)); - BOOST_REQUIRE_EQUAL(response.second, method == boost::beast::http::verb::head ? ""s : File::getFile(serverProcess.testConfigFilename)); + BOOST_REQUIRE_EQUAL(response.first, fmt::format("HTTP/{} 200 OK\r\nServer: Reichwein.IT Webserver " VERSION "\r\nContent-Type: application/text\r\nContent-Length: {}\r\n\r\n", http11 ? "1.1" : "1.0", method == boost::beast::http::verb::head ? 0 : size)); + BOOST_REQUIRE_EQUAL(response.second, method == boost::beast::http::verb::head ? ""s : File::getFile(testConfigFilename)); } -#endif } BOOST_DATA_TEST_CASE_F(Fixture, http_get_file_not_found, data::make({false, true}) * data::make({false, true}) * data::make({false, true}) * data::make({boost::beast::http::verb::head, boost::beast::http::verb::get}), ipv6, http11, https, method) { - std::cout << "DEBUGe: " << ipv6 << " " << http11 << " " << https << " " << method << std::endl; WebserverProcess serverProcess; BOOST_REQUIRE(serverProcess.isRunning()); -- cgit v1.2.3