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 <fstream>
#include <map>
#include <CXXTerminal/Terminal.h>
#include <spdlog/spdlog.h>
#include <experimental/filesystem>
#include <StringVariable.h>
@ -66,8 +67,15 @@ namespace logger {
if(!logFile.parent_path().empty())
fs::create_directories(logFile.parent_path());
try {
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 {
path = "/dev/null (" + to_string(serverId) + ")";
}
@ -140,6 +148,7 @@ namespace logger {
loggerEntry.second.reset();
}
loggers.clear();
spdlog::drop_all();
logConfig = nullptr;
terminalSink = nullptr;

View File

@ -15,6 +15,19 @@ namespace hex {
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);
}
}

View File

@ -111,11 +111,18 @@ do { \
return nullptr; \
} 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);
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;
}
@ -123,10 +130,59 @@ std::shared_ptr<SSLKeyPair> SSLManager::initializeSSLKey(const std::string &key,
auto load = this->loadSSL(rsaKey, error, raw);
if(!load) return nullptr;
{
lock_guard lock{this->context_lock};
this->rsa[key] = 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() {
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
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<BIO> certBio = nullptr;
std::shared_ptr<BIO> keyBio = nullptr;
std::shared_ptr<X509> cert = nullptr;
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> bio_certificate = nullptr;
std::shared_ptr<BIO> bio_private_key = nullptr;
std::shared_ptr<X509> certificate = nullptr;
std::shared_ptr<EVP_PKEY> key = nullptr;
bool flagCertModified = false;
bool flagKeyModified = false;
bool allow_generate_cert{false}, allow_generate_key{false};
bool certificate_modified{false}, key_modified{false};
std::shared_ptr<SSL_CTX> context = nullptr;
std::shared_ptr<SSLContext> result = nullptr;
if(rawData) {
certBio = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free);
BIO_write(certBio.get(), rawCert.c_str(), rawCert.length());
if(is_raw) {
if(!rawKey.empty()) {
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);
BIO_write(keyBio.get(), rawKey.c_str(), rawKey.length());
if(!rawCert.empty()) {
bio_certificate = shared_ptr<BIO>(BIO_new_mem_buf(rawCert.data(), rawCert.length()), ::BIO_free);
} else {
auto keyPath = fs::u8path(rawKey);
auto certPath = fs::u8path(rawCert);
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 {
auto key_path = fs::u8path(rawKey);
auto certificate_path = fs::u8path(rawCert);
if(!fs::exists(keyPath)) {
if(!generator) {
error = "Missing key file";
auto key_exists = fs::exists(key_path);
auto certificate_exists = fs::exists(certificate_path);
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;
}
std::ofstream {key_path};
allow_generate_key = true;
}
if(!certificate_exists) {
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()));
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;
}
std::ofstream {certificate_path};
allow_generate_cert = true;
} else if(!key_exists) {
error = "missing private key";
return nullptr;
}
{
std::ofstream { keyPath };
}
}
if(!fs::exists(certPath)) {
if(!generator) {
error = "Missing certificate file";
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()));
auto mode = allow_generate_cert ? "rw" : "r";
bio_certificate = shared_ptr<BIO>(BIO_new_file(rawCert.c_str(), mode), ::BIO_free);
if(!bio_certificate) SSL_ERROR("Could not open certificate: ");
}
{
std::ofstream { certPath };
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: ");
}
}
auto mode = generator ? "rw" : "r";
certBio = shared_ptr<BIO>(BIO_new_file(rawCert.c_str(), mode), ::BIO_free);
if(!certBio) SSL_ERROR("Could not load certificate: ");
keyBio = shared_ptr<BIO>(BIO_new_file(rawKey.c_str(), mode), ::BIO_free);
if(!keyBio) SSL_ERROR("Could not load key: ");
}
certificate = shared_ptr<X509>(PEM_read_bio_X509(bio_certificate.get(), nullptr, nullptr, nullptr), ::X509_free);
if(!certificate && (!generator || !allow_generate_cert)) SSL_ERROR("Could not read certificate: ");
cert = shared_ptr<X509>(PEM_read_bio_X509(certBio.get(), nullptr, nullptr, nullptr), ::X509_free);
if(!cert && !generator) SSL_ERROR("Could not read certificate: ");
key = shared_ptr<EVP_PKEY>(PEM_read_bio_PrivateKey(keyBio.get(), nullptr, nullptr, nullptr), ::EVP_PKEY_free);
if(!key && !generator) SSL_ERROR("Could not read key: ");
key = shared_ptr<EVP_PKEY>(PEM_read_bio_PrivateKey(bio_private_key.get(), nullptr, nullptr, nullptr), ::EVP_PKEY_free);
if(!key && (!generator || !allow_generate_key)) SSL_ERROR("Could not read key: ");
if(!key) {
key = shared_ptr<EVP_PKEY>(generator->generateKey(), ::EVP_PKEY_free);
flagKeyModified = true;
key_modified = true;
}
if(!cert) {
cert = shared_ptr<X509>(generator->generateCertificate(key.get()), ::X509_free);
flagCertModified = true;
if(!certificate) {
certificate = shared_ptr<X509>(generator->generateCertificate(key.get()), ::X509_free);
certificate_modified = true;
}
//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_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->context = context;
result->certificate = cert;
result->certificate = certificate;
result->privateKey = key;
if(flagCertModified) {
if(!rawData) {
certBio = shared_ptr<BIO>(BIO_new_file(rawCert.c_str(), "w"), ::BIO_free);
if(PEM_write_bio_X509(certBio.get(), cert.get()) != 1) SSL_ERROR("Could not write new certificate: ");
flagCertModified = false;
if(key_modified) {
if(!is_raw) {
bio_private_key = shared_ptr<BIO>(BIO_new_file(rawKey.c_str(), "w"), ::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: ");
} else {
assert(false); //TODO implement with membuf
/*
void* ptr = nullptr;
auto length = BIO_get_mem_data(certBio, &ptr);
if(!ptr) SSL_ERROR("Could not get cert bio mem pointer: ");
if(length <= 0) SSL_ERROR("Could not get cert bio mem length (" + to_string(length) + "): ");
rawCert.reserve(length);
memcpy((void*) rawCert.data(), ptr, length);
*/
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: ");
const uint8_t* mem_ptr{nullptr};
size_t length{0};
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 private key mem pointer/invalid length: ");
rawKey.reserve(length);
memcpy(rawKey.data(), mem_ptr, length);
}
}
if(flagKeyModified) {
if(!rawData) {
keyBio = shared_ptr<BIO>(BIO_new_file(rawKey.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: ");
flagKeyModified = false;
if(certificate_modified) {
if(!is_raw) {
bio_certificate = shared_ptr<BIO>(BIO_new_file(rawCert.c_str(), "w"), ::BIO_free);
if(PEM_write_bio_X509(bio_certificate.get(), certificate.get()) != 1) SSL_ERROR("Could not write new certificate: ");
} else {
assert(false); //TODO implement with membuf
/*
void* ptr = nullptr;
auto length = BIO_get_mem_data(certBio, &ptr);
if(!ptr) SSL_ERROR("Could not get cert bio mem pointer: ");
if(length <= 0) SSL_ERROR("Could not get cert bio mem length (" + to_string(length) + "): ");
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: ");
const uint8_t* mem_ptr{nullptr};
size_t length{0};
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);
memcpy((void*) rawCert.data(), ptr, length);
*/
memcpy(rawCert.data(), mem_ptr, length);
}
}
return result;
}
std::shared_ptr<SSLKeyPair> SSLManager::loadSSL(const std::string &rawKey, std::string &error, bool rawData, bool readPublic) {
std::shared_ptr<BIO> keyBio = nullptr;
std::shared_ptr<EVP_PKEY> key = nullptr;
std::shared_ptr<SSLKeyPair> result = make_shared<SSLKeyPair>();
std::shared_ptr<SSLKeyPair> SSLManager::loadSSL(const std::string &key_data, std::string &error, bool rawData, bool readPublic) {
std::shared_ptr<BIO> key_bio{nullptr};
std::shared_ptr<EVP_PKEY> key{nullptr};
auto result = make_shared<SSLKeyPair>();
// SSL_CTX_set_ecdh_auto(ctx, 1);
if(rawData) {
keyBio = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free);
BIO_write(keyBio.get(), rawKey.c_str(), rawKey.length());
key_bio = shared_ptr<BIO>(BIO_new(BIO_s_mem()), ::BIO_free);
BIO_write(key_bio.get(), key_data.c_str(), key_data.length());
} else {
auto keyPath = fs::u8path(rawKey);
auto key_path = fs::u8path(key_data);
if(!fs::exists(keyPath)) {
if(!fs::exists(key_path)) {
try {
if(keyPath.has_parent_path())
fs::create_directories(keyPath.parent_path());
if(key_path.has_parent_path())
fs::create_directories(key_path.parent_path());
} catch (fs::filesystem_error& error) {
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);
if(!keyBio) SSL_ERROR("Could not load key: ");
key_bio = shared_ptr<BIO>(BIO_new_file(key_data.c_str(), "r"), ::BIO_free);
if(!key_bio) SSL_ERROR("Could not load key: ");
}
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
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;
if(!key) {
if(readPublic) {
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;
@ -352,15 +419,16 @@ std::shared_ptr<pipes::SSL::Options> SSLManager::web_ssl_options() {
this->_web_options->context_method = TLS_method();
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) {
auto name = context.first;
if(name.length() < web_prefix.length())
if(name.length() < this->web_ctx_prefix.length())
continue;
if(name.substr(0, web_prefix.length()) != web_prefix)
if(name.substr(0, this->web_ctx_prefix.length()) != this->web_ctx_prefix)
continue;
auto servername = context.first.substr(web_prefix.length());
auto servername = context.first.substr(this->web_ctx_prefix.length());
if(servername == "default") {
this->_web_options->default_keypair({context.second->privateKey, context.second->certificate});
} else {

View File

@ -6,12 +6,11 @@
#include <map>
#include <pipes/ssl.h>
namespace ts {
namespace ssl {
namespace ts::ssl {
struct SSLContext {
std::shared_ptr<SSL_CTX> context = nullptr;
std::shared_ptr<EVP_PKEY> privateKey = nullptr;
std::shared_ptr<X509> certificate = nullptr;
std::shared_ptr<SSL_CTX> context{nullptr};
std::shared_ptr<EVP_PKEY> privateKey{nullptr};
std::shared_ptr<X509> certificate{nullptr};
};
struct SSLGenerator {
@ -35,6 +34,10 @@ namespace ts {
bool initialize();
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<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"); }
private:
std::mutex context_lock{};
std::map<std::string, std::shared_ptr<SSLContext>> contexts;
std::map<std::string, std::shared_ptr<SSLKeyPair>> rsa;
std::mutex _web_options_lock;
bool _web_disabled = false;
const std::string web_ctx_prefix{"web_"};
std::mutex _web_options_lock{};
bool _web_disabled{false};
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<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);
};
}
}