Validate SSL configuration

This commit is contained in:
badaix 2025-01-05 17:52:31 +01:00
parent ce743ce4c6
commit e0443f6e5f
3 changed files with 56 additions and 12 deletions

View file

@ -52,6 +52,8 @@
[ssl]
# https://deliciousbrains.com/ssl-certificate-authority-for-local-https-development/
# https://gist.github.com/fntlnz/cf14feb5a46b2eda428e000157447309
# Certificate files are either specified by their full or relative path. Certificates with
# relative path are searched for in the current path and in "/etc/snapserver/certs"
# Certificate file in PEM format
# certificate =

View file

@ -24,6 +24,7 @@
// standard headers
#include <cstdint>
#include <filesystem>
#include <string>
#include <vector>
@ -35,20 +36,25 @@ struct ServerSettings
int threads{-1};
std::string pid_file{"/var/run/snapserver/pid"};
std::string user{"snapserver"};
std::string group{""};
std::string data_dir{""};
std::string group;
std::string data_dir;
};
struct Ssl
{
std::string certificate{""};
std::string certificate_key{""};
std::string key_password{""};
std::filesystem::path certificate;
std::filesystem::path certificate_key;
std::string key_password;
bool enabled() const
{
return !certificate.empty() && !certificate_key.empty();
}
};
struct User
{
User(const std::string& user_permissions_password)
explicit User(const std::string& user_permissions_password)
{
std::string perm;
name = utils::string::split_left(user_permissions_password, ':', perm);
@ -71,9 +77,9 @@ struct ServerSettings
size_t ssl_port{1788};
std::vector<std::string> bind_to_address{{"::"}};
std::vector<std::string> ssl_bind_to_address{{"::"}};
std::string doc_root{""};
std::string doc_root;
std::string host{"<hostname>"};
std::string url_prefix{""};
std::string url_prefix;
};
struct Tcp
@ -102,7 +108,7 @@ struct ServerSettings
struct Logging
{
std::string sink{""};
std::string sink;
std::string filter{"*:info"};
};

View file

@ -18,6 +18,7 @@
// local headers
#include "common/popl.hpp"
#include <filesystem>
#ifdef HAS_DAEMON
#include "common/daemon.hpp"
#endif
@ -81,12 +82,14 @@ int main(int argc, char* argv[])
conf.add<Implicit<string>>("", "server.datadir", "directory where persistent data is stored", settings.server.data_dir, &settings.server.data_dir);
// SSL settings
conf.add<Value<string>>("", "ssl.certificate", "certificate file (PEM format)", settings.ssl.certificate, &settings.ssl.certificate);
conf.add<Value<string>>("", "ssl.certificate_key", "private key file (PEM format)", settings.ssl.certificate_key, &settings.ssl.certificate_key);
conf.add<Value<std::filesystem::path>>("", "ssl.certificate", "certificate file (PEM format)", settings.ssl.certificate, &settings.ssl.certificate);
conf.add<Value<std::filesystem::path>>("", "ssl.certificate_key", "private key file (PEM format)", settings.ssl.certificate_key, &settings.ssl.certificate_key);
conf.add<Value<string>>("", "ssl.key_password", "key password (for encrypted private key)", settings.ssl.key_password, &settings.ssl.key_password);
#if 0 // feature: users
// Users setting
auto users_value = conf.add<Value<string>>("", "users.user", "<User nane>:<permissions>:<password>");
#endif
// HTTP RPC settings
conf.add<Value<bool>>("", "http.enabled", "enable HTTP Json RPC (HTTP POST and websockets)", settings.http.enabled, &settings.http.enabled);
@ -253,8 +256,40 @@ int main(int argc, char* argv[])
else
throw SnapException("Invalid log sink: " + settings.logging.sink);
if (!settings.ssl.certificate.empty() && !settings.ssl.certificate_key.empty())
{
namespace fs = std::filesystem;
auto make_absolute = [](const fs::path& filename) {
const fs::path cert_path = "/etc/snapserver/certs/";
if (filename.is_absolute())
return filename;
if (fs::exists(filename))
return fs::canonical(filename);
return cert_path / filename;
};
settings.ssl.certificate = make_absolute(settings.ssl.certificate);
if (!fs::exists(settings.ssl.certificate))
throw SnapException("SSL certificate file not found: " + settings.ssl.certificate.native());
settings.ssl.certificate_key = make_absolute(settings.ssl.certificate_key);
if (!fs::exists(settings.ssl.certificate_key))
throw SnapException("SSL certificate_key file not found: " + settings.ssl.certificate_key.native());
}
else if (settings.ssl.certificate.empty() != settings.ssl.certificate_key.empty())
{
throw SnapException("Both SSL 'certificate' and 'certificate_key' must be set or empty");
}
if (!settings.ssl.enabled())
{
if (settings.http.ssl_enabled)
throw SnapException("HTTPS enabled ([http] ssl_enabled), but no certificates specified");
}
LOG(INFO, LOG_TAG) << "Version " << version::code << (!version::rev().empty() ? (", revision " + version::rev(8)) : ("")) << "\n";
if (settings.ssl.enabled())
LOG(INFO, LOG_TAG) << "SSL enabled - certificate file: '" << settings.ssl.certificate.native() << "', certificate key file: '" << settings.ssl.certificate_key.native() << "'\n";
if (!streamValue->is_set() && !sourceValue->is_set())
settings.stream.sources.push_back(sourceValue->value());
@ -269,6 +304,7 @@ int main(int argc, char* argv[])
settings.stream.sources.push_back(sourceValue->value(n));
}
#if 0 // feature: users
for (size_t n = 0; n < users_value->count(); ++n)
{
settings.users.emplace_back(users_value->value(n));
@ -276,7 +312,7 @@ int main(int argc, char* argv[])
<< ", permissions: " << utils::string::container_to_string(settings.users.back().permissions)
<< ", pw: " << settings.users.back().password << "\n";
}
#endif
#ifdef HAS_DAEMON
std::unique_ptr<Daemon> daemon;