diff options
| author | Roland Reichwein <mail@reichwein.it> | 2023-01-07 12:09:14 +0100 | 
|---|---|---|
| committer | Roland Reichwein <mail@reichwein.it> | 2023-01-07 12:09:14 +0100 | 
| commit | edb8e44b5a12776a6b5ce4bb5316e4c8acdd858a (patch) | |
| tree | e92630b31192589b3c5e184b7045f8802dc40cd2 | |
| parent | 1e6cca9ca8c4771b05f419a23cd3bb1bbc1f0e38 (diff) | |
Fix TLS certificate verification
| -rw-r--r-- | https.cpp | 17 | ||||
| -rw-r--r-- | tests/test-webserver.cpp | 78 | 
2 files changed, 79 insertions, 16 deletions
@@ -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<ssl::context> 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(<webserver> @@ -74,8 +77,8 @@ public:      <plugin>static-files</plugin>      <target>.</target>     </path> -   <certpath>../fullchain.pem</certpath> -   <keypath>../privkey.pem</keypath> +   <certpath>testchain.pem</certpath> +   <keypath>testkey.pem</keypath>    </site>   </sites>   <sockets> @@ -105,9 +108,57 @@ public:    </socket>   </sockets>  </webserver> -  )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<std::string,std::string> 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<std::string,std::string> 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<std::string,std::string> 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());  | 
