diff options
Diffstat (limited to 'lib/pluginloader/pluginloader.cpp')
-rw-r--r-- | lib/pluginloader/pluginloader.cpp | 107 |
1 files changed, 57 insertions, 50 deletions
diff --git a/lib/pluginloader/pluginloader.cpp b/lib/pluginloader/pluginloader.cpp index e5c4b89..082a449 100644 --- a/lib/pluginloader/pluginloader.cpp +++ b/lib/pluginloader/pluginloader.cpp @@ -1,38 +1,45 @@ /* * This file is part of smolbote. It's copyrighted by the contributors recorded * in the version control history of the file, available from its original - * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote + * location: https://library.iserlohn-fortress.net/aqua/smolbote.git * * SPDX-License-Identifier: GPL-3.0 */ #include "pluginloader.h" +#include "publicKey.h" #include <QFile> +#include <filesystem> +#include <fstream> #include <openssl/evp.h> #include <openssl/pem.h> -#include "publicKey.h" - -PluginLoader::PluginLoader(const QString &fileName, PluginLoader::SignatureState state, QObject *parent) - : QPluginLoader(fileName, parent) - , m_state(state) -{ -} bool PluginLoader::verify(const char *hashName) { - const QString sigName = this->fileName() + ".sig"; - if(!QFile::exists(sigName)) { - if(m_state.ignored || m_state.checked) - return true; - - m_sigError = tr("A signature is required, but none was found."); + const std::filesystem::path plugin_path(fileName().toStdString()); + if(!std::filesystem::is_regular_file(plugin_path)) { + m_sigError = tr("A plugin is required, but none was found."); return false; } + if(m_state <= SigIgnored) { + return true; + } + + const std::filesystem::path signature_path(fileName().toStdString() + ".sig"); + if(!std::filesystem::is_regular_file(signature_path)) { + if(m_state >= SigEnforced) { + m_sigError = tr("A signature is required, but none was found."); + return false; + } + + return true; + } + auto *bio = BIO_new_mem_buf(publicKey_pem, publicKey_pem_len); Q_CHECK_PTR(bio); - auto *key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + auto *key = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); Q_CHECK_PTR(key); auto *ctx = EVP_MD_CTX_new(); @@ -41,53 +48,53 @@ bool PluginLoader::verify(const char *hashName) const auto *md = EVP_get_digestbyname(hashName); Q_CHECK_PTR(md); - int rc = EVP_DigestVerifyInit(ctx, NULL, md, NULL, key); + int rc = EVP_DigestVerifyInit(ctx, nullptr, md, nullptr, key); if(rc != 1) { m_sigError = tr("Failed to compute signature (stage=init)"); return false; } // read plugin into DigestVerifyUpdate - QFile plugin(this->fileName()); - plugin.open(QIODevice::ReadOnly); - int len = plugin.size(); - int read = 0; - auto *buf = new unsigned char[1024]; - while(len > 0) { - read = plugin.read(reinterpret_cast<char*>(buf), 1024); - len -= read; - - rc = EVP_DigestVerifyUpdate(ctx, buf, read); - if(rc != 1) { - m_sigError = tr("Failed to compute signature (staga=update)"); - return false; + { + std::ifstream plugin(plugin_path, std::ios::binary); + plugin.unsetf(std::ios::skipws); + if(!plugin.is_open()) { + m_sigError = tr("Cannot read plugin during signature check"); + return true; + } + + const std::size_t buffer_size = 1024; + std::vector<char> buffer(buffer_size); + while(const auto sz = plugin.readsome(&buffer.front(), buffer_size)) { + rc = EVP_DigestVerifyUpdate(ctx, reinterpret_cast<unsigned char *>(buffer.data()), sz); + if(rc != 1) { + m_sigError = tr("Failed to compute signature (stage=update)"); + return false; + } } } - delete[] buf; - plugin.close(); // read signature into DigestVerifyFinal - QFile sigFile(sigName); - sigFile.open(QIODevice::ReadOnly); - const int sig_len = sigFile.size(); - const auto* sig = [&sigFile, sig_len]() { - auto* buf = new unsigned char[sig_len]; - sigFile.read(reinterpret_cast<char*>(buf), sig_len); - return buf; - }(); - sigFile.close(); - - rc = EVP_DigestVerifyFinal(ctx, sig, sig_len); - delete sig; - - if(rc == 1) - return true; - else { - if(m_state.ignored) - return true; + { + std::ifstream signature(signature_path, std::ios::binary); + signature.unsetf(std::ios::skipws); + if(!signature.is_open()) { + m_sigError = tr("Cannot read signature during signature check"); + return false; + } + + const auto buffer_size = std::filesystem::file_size(signature_path); + std::vector<unsigned char> buffer(buffer_size); + buffer.insert(buffer.begin(), std::istream_iterator<unsigned char>(signature), std::istream_iterator<unsigned char>()); + signature.close(); + + rc = EVP_DigestVerifyFinal(ctx, buffer.data(), buffer_size); + } + + if(rc != 1) { m_sigError = tr("Signature does not match"); return false; } + return true; } - |