A lot of updates

This commit is contained in:
WolverinDEV 2019-11-22 20:50:58 +01:00
parent 2cae73c51a
commit 4d64f60f18
4 changed files with 208 additions and 114 deletions

View File

@ -3,6 +3,7 @@
#include <iomanip> #include <iomanip>
#include <fstream> #include <fstream>
#include <map> #include <map>
#include <CXXTerminal/Terminal.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <experimental/filesystem> #include <experimental/filesystem>
#include <StringVariable.h> #include <StringVariable.h>
@ -66,8 +67,15 @@ namespace logger {
if(!logFile.parent_path().empty()) if(!logFile.parent_path().empty())
fs::create_directories(logFile.parent_path()); fs::create_directories(logFile.parent_path());
auto fileSink = make_shared<ColoredFileSink>(logFile.string(), 1024 * 1024 * 50, 12); try {
sinks.push_back(fileSink); auto fileSink = make_shared<ColoredFileSink>(logFile.string(), 1024 * 1024 * 50, 12);
sinks.push_back(fileSink);
} catch(std::exception& ex) {
if(group != 0 && group != -1)
logger(0)->critical("Failed to create file for new log group: {}", ex.what());
else
terminal::instance()->writeMessage("§4[CRITICAL] §eFailed to create main log file: " + string{ex.what()}, false);
}
} else { } else {
path = "/dev/null (" + to_string(serverId) + ")"; path = "/dev/null (" + to_string(serverId) + ")";
} }
@ -140,6 +148,7 @@ namespace logger {
loggerEntry.second.reset(); loggerEntry.second.reset();
} }
loggers.clear(); loggers.clear();
spdlog::drop_all();
logConfig = nullptr; logConfig = nullptr;
terminalSink = nullptr; terminalSink = nullptr;

View File

@ -15,6 +15,19 @@ namespace hex {
output[idx++] = static_cast<char>(beg + ((elm & 0x0F) >> 0)); output[idx++] = static_cast<char>(beg + ((elm & 0x0F) >> 0));
} }
return std::string(output, len);
}
inline std::string hex(const std::string& input){
size_t len = input.length() * 2;
char output[len];
size_t idx = 0;
for (char elm : input) {
auto lower = ((uint8_t) elm >> 4U) & 0xFU;
auto upper = ((uint8_t) elm & 0xFU) >> 0U;
output[idx++] = static_cast<char>(lower > 9 ? 'a' + (lower - 9) : '0' + lower);
output[idx++] = static_cast<char>(upper > 9 ? 'a' + (upper - 9) : '0' + upper);
}
return std::string(output, len); return std::string(output, len);
} }
} }

View File

@ -111,11 +111,18 @@ do { \
return nullptr; \ return nullptr; \
} while(false) } while(false)
std::shared_ptr<SSLContext> SSLManager::initializeContext(const std::string &key, std::string &privateKey, std::string &certificate, std::string &error, bool raw, const std::shared_ptr<SSLGenerator>& generator) { std::shared_ptr<SSLContext> SSLManager::initializeContext(const std::string &context, std::string &privateKey, std::string &certificate, std::string &error, bool raw, const std::shared_ptr<SSLGenerator>& generator) {
auto load = this->loadContext(privateKey, certificate, error, raw, generator); auto load = this->loadContext(privateKey, certificate, error, raw, generator);
if(!load) return nullptr; if(!load) return nullptr;
this->contexts[key] = load; {
lock_guard lock{this->context_lock};
this->contexts[context] = load;
}
if(context.find(this->web_ctx_prefix) == 0) {
lock_guard lock{this->_web_options_lock};
this->_web_options.reset();
}
return load; return load;
} }
@ -123,10 +130,59 @@ std::shared_ptr<SSLKeyPair> SSLManager::initializeSSLKey(const std::string &key,
auto load = this->loadSSL(rsaKey, error, raw); auto load = this->loadSSL(rsaKey, error, raw);
if(!load) return nullptr; if(!load) return nullptr;
this->rsa[key] = load; {
lock_guard lock{this->context_lock};
this->rsa[key] = load;
}
return load; return load;
} }
bool SSLManager::rename_context(const std::string &old_name, const std::string &new_name) {
{
lock_guard lock{this->context_lock};
if(this->contexts.count(old_name) == 0)
return false;
auto old = std::move(this->contexts[old_name]);
this->contexts.erase(old_name);
this->contexts[new_name] = std::move(old);
}
if(old_name.find(this->web_ctx_prefix) == 0 || new_name.find(this->web_ctx_prefix) == 0) {
lock_guard lock{this->_web_options_lock};
this->_web_options.reset();
}
return true;
}
bool SSLManager::unregister_context(const std::string &context) {
{
lock_guard lock{this->context_lock};
if(this->contexts.erase(context) == 0)
return false;
}
if(context.find(this->web_ctx_prefix) == 0) {
lock_guard lock{this->_web_options_lock};
this->_web_options.reset();
}
return true;
}
void SSLManager::unregister_web_contexts() {
{
lock_guard lock{this->context_lock};
decltype(this->contexts) ctxs{this->contexts};
for(auto& [key, _] : ctxs) {
(void) _;
if(key.find(this->web_ctx_prefix) == 0) {
this->contexts.erase(key);
}
}
}
lock_guard lock{this->_web_options_lock};
this->_web_options.reset();
}
EVP_PKEY* SSLGenerator::generateKey() { EVP_PKEY* SSLGenerator::generateKey() {
auto key = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>(EVP_PKEY_new(), ::EVP_PKEY_free); auto key = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>(EVP_PKEY_new(), ::EVP_PKEY_free);
@ -164,82 +220,95 @@ X509* SSLGenerator::generateCertificate(EVP_PKEY* key) {
} }
//TODO passwords //TODO passwords
std::shared_ptr<SSLContext> SSLManager::loadContext(std::string &rawKey, std::string &rawCert, std::string &error, bool rawData, const shared_ptr<SSLGenerator>& generator) { std::shared_ptr<SSLContext> SSLManager::loadContext(std::string &rawKey, std::string &rawCert, std::string &error, bool is_raw, const shared_ptr<SSLGenerator>& generator) {
std::shared_ptr<BIO> certBio = nullptr; std::shared_ptr<BIO> bio_certificate = nullptr;
std::shared_ptr<BIO> keyBio = nullptr; std::shared_ptr<BIO> bio_private_key = nullptr;
std::shared_ptr<X509> cert = nullptr; std::shared_ptr<X509> certificate = nullptr;
std::shared_ptr<EVP_PKEY> key = nullptr; std::shared_ptr<EVP_PKEY> key = nullptr;
bool flagCertModified = false; bool allow_generate_cert{false}, allow_generate_key{false};
bool flagKeyModified = false; bool certificate_modified{false}, key_modified{false};
std::shared_ptr<SSL_CTX> context = nullptr; std::shared_ptr<SSL_CTX> context = nullptr;
std::shared_ptr<SSLContext> result = nullptr; std::shared_ptr<SSLContext> result = nullptr;
if(rawData) { if(is_raw) {
certBio = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free); if(!rawKey.empty()) {
BIO_write(certBio.get(), rawCert.c_str(), rawCert.length()); bio_private_key = shared_ptr<BIO>(BIO_new_mem_buf(rawKey.data(), rawKey.length()), ::BIO_free);
keyBio = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free); if(!rawCert.empty()) {
BIO_write(keyBio.get(), rawKey.c_str(), rawKey.length()); bio_certificate = shared_ptr<BIO>(BIO_new_mem_buf(rawCert.data(), rawCert.length()), ::BIO_free);
} else {
allow_generate_cert = true;
}
} else {
allow_generate_cert = true;
allow_generate_key = true;
}
if(!bio_certificate) bio_certificate = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free);
if(!bio_private_key) bio_private_key = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free);
} else { } else {
auto keyPath = fs::u8path(rawKey); auto key_path = fs::u8path(rawKey);
auto certPath = fs::u8path(rawCert); auto certificate_path = fs::u8path(rawCert);
if(!fs::exists(keyPath)) { auto key_exists = fs::exists(key_path);
if(!generator) { auto certificate_exists = fs::exists(certificate_path);
error = "Missing key file";
if(!key_exists) {
try {
if(key_path.has_parent_path())
fs::create_directories(key_path.parent_path());
} catch (fs::filesystem_error& ex) {
error = "failed to create keys file parent path: " + std::string{ex.what()};
return nullptr; return nullptr;
} }
try {
if(keyPath.has_parent_path())
fs::create_directories(keyPath.parent_path());
} catch (fs::filesystem_error& error) {
logError("Could not create key directory: " + string(error.what()));
}
{ std::ofstream {key_path};
std::ofstream { keyPath }; allow_generate_key = true;
}
} }
if(!fs::exists(certPath)) { if(!certificate_exists) {
if(!generator) { try {
error = "Missing certificate file"; if(certificate_path.has_parent_path())
fs::create_directories(certificate_path.parent_path());
} catch (fs::filesystem_error& ex) {
error = "failed to create certificate file parent path: " + std::string{ex.what()};
return nullptr; return nullptr;
} }
try {
if(certPath.has_parent_path())
fs::create_directories(certPath.parent_path());
} catch (fs::filesystem_error& error) {
logError("Could not create certificate directory: " + string(error.what()));
}
{ std::ofstream {certificate_path};
std::ofstream { certPath }; allow_generate_cert = true;
} } else if(!key_exists) {
error = "missing private key";
return nullptr;
} }
auto mode = generator ? "rw" : "r"; {
certBio = shared_ptr<BIO>(BIO_new_file(rawCert.c_str(), mode), ::BIO_free); auto mode = allow_generate_cert ? "rw" : "r";
if(!certBio) SSL_ERROR("Could not load certificate: "); bio_certificate = shared_ptr<BIO>(BIO_new_file(rawCert.c_str(), mode), ::BIO_free);
keyBio = shared_ptr<BIO>(BIO_new_file(rawKey.c_str(), mode), ::BIO_free); if(!bio_certificate) SSL_ERROR("Could not open certificate: ");
if(!keyBio) SSL_ERROR("Could not load key: "); }
{
auto mode = allow_generate_key ? "rw" : "r";
bio_private_key = shared_ptr<BIO>(BIO_new_file(rawKey.c_str(), mode), ::BIO_free);
if(!bio_private_key) SSL_ERROR("Could not open key: ");
}
} }
cert = shared_ptr<X509>(PEM_read_bio_X509(certBio.get(), nullptr, nullptr, nullptr), ::X509_free); certificate = shared_ptr<X509>(PEM_read_bio_X509(bio_certificate.get(), nullptr, nullptr, nullptr), ::X509_free);
if(!cert && !generator) SSL_ERROR("Could not read certificate: "); if(!certificate && (!generator || !allow_generate_cert)) SSL_ERROR("Could not read certificate: ");
key = shared_ptr<EVP_PKEY>(PEM_read_bio_PrivateKey(keyBio.get(), nullptr, nullptr, nullptr), ::EVP_PKEY_free); key = shared_ptr<EVP_PKEY>(PEM_read_bio_PrivateKey(bio_private_key.get(), nullptr, nullptr, nullptr), ::EVP_PKEY_free);
if(!key && !generator) SSL_ERROR("Could not read key: "); if(!key && (!generator || !allow_generate_key)) SSL_ERROR("Could not read key: ");
if(!key) { if(!key) {
key = shared_ptr<EVP_PKEY>(generator->generateKey(), ::EVP_PKEY_free); key = shared_ptr<EVP_PKEY>(generator->generateKey(), ::EVP_PKEY_free);
flagKeyModified = true; key_modified = true;
} }
if(!cert) { if(!certificate) {
cert = shared_ptr<X509>(generator->generateCertificate(key.get()), ::X509_free); certificate = shared_ptr<X509>(generator->generateCertificate(key.get()), ::X509_free);
flagCertModified = true; certificate_modified = true;
} }
//Create context //Create context
@ -248,88 +317,86 @@ std::shared_ptr<SSLContext> SSLManager::loadContext(std::string &rawKey, std::st
if (SSL_CTX_use_PrivateKey(context.get(), key.get()) <= 0) SSL_ERROR("Could not use private key: "); if (SSL_CTX_use_PrivateKey(context.get(), key.get()) <= 0) SSL_ERROR("Could not use private key: ");
if (SSL_CTX_use_certificate(context.get(), cert.get()) <= 0) SSL_ERROR("Could not use certificate: "); if (SSL_CTX_use_certificate(context.get(), certificate.get()) <= 0) SSL_ERROR("Could not use certificate: ");
result = std::make_shared<SSLContext>(); result = std::make_shared<SSLContext>();
result->context = context; result->context = context;
result->certificate = cert; result->certificate = certificate;
result->privateKey = key; result->privateKey = key;
if(flagCertModified) { if(key_modified) {
if(!rawData) { if(!is_raw) {
certBio = shared_ptr<BIO>(BIO_new_file(rawCert.c_str(), "w"), ::BIO_free); bio_private_key = shared_ptr<BIO>(BIO_new_file(rawKey.c_str(), "w"), ::BIO_free);
if(PEM_write_bio_X509(certBio.get(), cert.get()) != 1) SSL_ERROR("Could not write new certificate: "); if(PEM_write_bio_PrivateKey(bio_private_key.get(), key.get(), nullptr, nullptr, 0, nullptr, nullptr) != 1) SSL_ERROR("Could not write new key: ");
flagCertModified = false;
} else { } else {
assert(false); //TODO implement with membuf bio_private_key = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free);
/* if(PEM_write_bio_PrivateKey(bio_private_key.get(), key.get(), nullptr, nullptr, 0, nullptr, nullptr) != 1) SSL_ERROR("Could not write new key: ");
void* ptr = nullptr;
auto length = BIO_get_mem_data(certBio, &ptr); const uint8_t* mem_ptr{nullptr};
if(!ptr) SSL_ERROR("Could not get cert bio mem pointer: "); size_t length{0};
if(length <= 0) SSL_ERROR("Could not get cert bio mem length (" + to_string(length) + "): "); if(!BIO_mem_contents(&*bio_private_key, &mem_ptr, &length)) SSL_ERROR("Failed to get mem contents: ");
rawCert.reserve(length); if(!mem_ptr || length < 0) SSL_ERROR("Could not get private key mem pointer/invalid length: ");
memcpy((void*) rawCert.data(), ptr, length); rawKey.reserve(length);
*/ memcpy(rawKey.data(), mem_ptr, length);
} }
} }
if(flagKeyModified) { if(certificate_modified) {
if(!rawData) { if(!is_raw) {
keyBio = shared_ptr<BIO>(BIO_new_file(rawKey.c_str(), "w"), ::BIO_free); bio_certificate = shared_ptr<BIO>(BIO_new_file(rawCert.c_str(), "w"), ::BIO_free);
if(PEM_write_bio_PrivateKey(keyBio.get(), key.get(), nullptr, nullptr, 0, nullptr, nullptr) != 1) SSL_ERROR("Could not write new key: "); if(PEM_write_bio_X509(bio_certificate.get(), certificate.get()) != 1) SSL_ERROR("Could not write new certificate: ");
flagKeyModified = false;
} else { } else {
assert(false); //TODO implement with membuf bio_certificate = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free);
/* if(PEM_write_bio_X509(bio_certificate.get(), certificate.get()) != 1) SSL_ERROR("Could not write new certificate: ");
void* ptr = nullptr;
auto length = BIO_get_mem_data(certBio, &ptr); const uint8_t* mem_ptr{nullptr};
if(!ptr) SSL_ERROR("Could not get cert bio mem pointer: "); size_t length{0};
if(length <= 0) SSL_ERROR("Could not get cert bio mem length (" + to_string(length) + "): "); if(!BIO_mem_contents(&*bio_private_key, &mem_ptr, &length)) SSL_ERROR("Failed to get mem contents: ");
if(!mem_ptr || length < 0) SSL_ERROR("Could not get cert bio mem pointer/invalid length: ");
rawCert.reserve(length); rawCert.reserve(length);
memcpy((void*) rawCert.data(), ptr, length); memcpy(rawCert.data(), mem_ptr, length);
*/
} }
} }
return result; return result;
} }
std::shared_ptr<SSLKeyPair> SSLManager::loadSSL(const std::string &rawKey, std::string &error, bool rawData, bool readPublic) { std::shared_ptr<SSLKeyPair> SSLManager::loadSSL(const std::string &key_data, std::string &error, bool rawData, bool readPublic) {
std::shared_ptr<BIO> keyBio = nullptr; std::shared_ptr<BIO> key_bio{nullptr};
std::shared_ptr<EVP_PKEY> key = nullptr; std::shared_ptr<EVP_PKEY> key{nullptr};
std::shared_ptr<SSLKeyPair> result = make_shared<SSLKeyPair>(); auto result = make_shared<SSLKeyPair>();
// SSL_CTX_set_ecdh_auto(ctx, 1); // SSL_CTX_set_ecdh_auto(ctx, 1);
if(rawData) { if(rawData) {
keyBio = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free); key_bio = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free);
BIO_write(keyBio.get(), rawKey.c_str(), rawKey.length()); BIO_write(key_bio.get(), key_data.c_str(), key_data.length());
} else { } else {
auto keyPath = fs::u8path(rawKey); auto key_path = fs::u8path(key_data);
if(!fs::exists(keyPath)) { if(!fs::exists(key_path)) {
try { try {
if(keyPath.has_parent_path()) if(key_path.has_parent_path())
fs::create_directories(keyPath.parent_path()); fs::create_directories(key_path.parent_path());
} catch (fs::filesystem_error& error) { } catch (fs::filesystem_error& error) {
logError("Could not create key directory: " + string(error.what())); logError("Could not create key directory: " + string(error.what()));
} }
{ {
std::ofstream { keyPath }; std::ofstream { key_path };
} }
} }
keyBio = shared_ptr<BIO>(BIO_new_file(rawKey.c_str(), "r"), ::BIO_free); key_bio = shared_ptr<BIO>(BIO_new_file(key_data.c_str(), "r"), ::BIO_free);
if(!keyBio) SSL_ERROR("Could not load key: "); if(!key_bio) SSL_ERROR("Could not load key: ");
} }
if(readPublic) if(readPublic)
key = shared_ptr<EVP_PKEY>(PEM_read_bio_PUBKEY(keyBio.get(), nullptr, nullptr, nullptr), ::EVP_PKEY_free); key = shared_ptr<EVP_PKEY>(PEM_read_bio_PUBKEY(key_bio.get(), nullptr, nullptr, nullptr), ::EVP_PKEY_free);
else else
key = shared_ptr<EVP_PKEY>(PEM_read_bio_PrivateKey(keyBio.get(), nullptr, nullptr, nullptr), ::EVP_PKEY_free); key = shared_ptr<EVP_PKEY>(PEM_read_bio_PrivateKey(key_bio.get(), nullptr, nullptr, nullptr), ::EVP_PKEY_free);
result->contains_private = !readPublic; result->contains_private = !readPublic;
if(!key) { if(!key) {
if(readPublic) { if(readPublic) {
SSL_ERROR("Could not read key!"); SSL_ERROR("Could not read key!");
} else return this->loadSSL(rawKey, error, rawData, true); } else return this->loadSSL(key_data, error, rawData, true);
} }
result->key = key; result->key = key;
@ -352,15 +419,16 @@ std::shared_ptr<pipes::SSL::Options> SSLManager::web_ssl_options() {
this->_web_options->context_method = TLS_method(); this->_web_options->context_method = TLS_method();
this->_web_options->free_unused_keypairs = false; /* we dont want our keys get removed */ this->_web_options->free_unused_keypairs = false; /* we dont want our keys get removed */
string web_prefix = "web_";
lock_guard ctx_lock{this->context_lock};
for(auto& context : this->contexts) { for(auto& context : this->contexts) {
auto name = context.first; auto name = context.first;
if(name.length() < web_prefix.length()) if(name.length() < this->web_ctx_prefix.length())
continue; continue;
if(name.substr(0, web_prefix.length()) != web_prefix) if(name.substr(0, this->web_ctx_prefix.length()) != this->web_ctx_prefix)
continue; continue;
auto servername = context.first.substr(web_prefix.length()); auto servername = context.first.substr(this->web_ctx_prefix.length());
if(servername == "default") { if(servername == "default") {
this->_web_options->default_keypair({context.second->privateKey, context.second->certificate}); this->_web_options->default_keypair({context.second->privateKey, context.second->certificate});
} else { } else {

View File

@ -6,12 +6,11 @@
#include <map> #include <map>
#include <pipes/ssl.h> #include <pipes/ssl.h>
namespace ts { namespace ts::ssl {
namespace ssl {
struct SSLContext { struct SSLContext {
std::shared_ptr<SSL_CTX> context = nullptr; std::shared_ptr<SSL_CTX> context{nullptr};
std::shared_ptr<EVP_PKEY> privateKey = nullptr; std::shared_ptr<EVP_PKEY> privateKey{nullptr};
std::shared_ptr<X509> certificate = nullptr; std::shared_ptr<X509> certificate{nullptr};
}; };
struct SSLGenerator { struct SSLGenerator {
@ -35,6 +34,10 @@ namespace ts {
bool initialize(); bool initialize();
void printDetails(); void printDetails();
bool unregister_context(const std::string& /* key */);
bool rename_context(const std::string& /* old key */, const std::string& /* new key */); /* if new already exists it will be dropped */
void unregister_web_contexts();
std::shared_ptr<SSLKeyPair> initializeSSLKey(const std::string &key, const std::string &rsaKey, std::string &error, bool raw = false); std::shared_ptr<SSLKeyPair> initializeSSLKey(const std::string &key, const std::string &rsaKey, std::string &error, bool raw = false);
std::shared_ptr<SSLContext> initializeContext(const std::string& key, std::string& privateKey, std::string& certificate, std::string& error, bool raw = false, const std::shared_ptr<SSLGenerator>& = nullptr); std::shared_ptr<SSLContext> initializeContext(const std::string& key, std::string& privateKey, std::string& certificate, std::string& error, bool raw = false, const std::shared_ptr<SSLGenerator>& = nullptr);
@ -48,15 +51,16 @@ namespace ts {
std::shared_ptr<SSLContext> getQueryContext() { return this->getContext("query"); } std::shared_ptr<SSLContext> getQueryContext() { return this->getContext("query"); }
private: private:
std::mutex context_lock{};
std::map<std::string, std::shared_ptr<SSLContext>> contexts; std::map<std::string, std::shared_ptr<SSLContext>> contexts;
std::map<std::string, std::shared_ptr<SSLKeyPair>> rsa; std::map<std::string, std::shared_ptr<SSLKeyPair>> rsa;
std::mutex _web_options_lock; const std::string web_ctx_prefix{"web_"};
bool _web_disabled = false; std::mutex _web_options_lock{};
bool _web_disabled{false};
std::shared_ptr<pipes::SSL::Options> _web_options; std::shared_ptr<pipes::SSL::Options> _web_options;
std::shared_ptr<SSLContext> loadContext(std::string& rawKey, std::string& rawCert, std::string& error, bool rawData = false, const std::shared_ptr<SSLGenerator>& = nullptr); std::shared_ptr<SSLContext> loadContext(std::string& rawKey, std::string& rawCert, std::string& error, bool rawData = false, const std::shared_ptr<SSLGenerator>& = nullptr);
std::shared_ptr<SSLKeyPair> loadSSL(const std::string &key, std::string &error, bool rawData = false, bool readPublic = false); std::shared_ptr<SSLKeyPair> loadSSL(const std::string &key_data, std::string &error, bool rawData = false, bool readPublic = false);
}; };
} }
}