summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2023-01-07 12:09:14 +0100
committerRoland Reichwein <mail@reichwein.it>2023-01-07 12:09:14 +0100
commitedb8e44b5a12776a6b5ce4bb5316e4c8acdd858a (patch)
treee92630b31192589b3c5e184b7045f8802dc40cd2
parent1e6cca9ca8c4771b05f419a23cd3bb1bbc1f0e38 (diff)
Fix TLS certificate verification
-rw-r--r--https.cpp17
-rw-r--r--tests/test-webserver.cpp78
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<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());