/* * 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://library.iserlohn-fortress.net/aqua/smolbote.git * * SPDX-License-Identifier: GPL-3.0 */ #include "pluginloader.h" #include "publicKey.h" #include #include #include #include #include bool PluginLoader::verify(const char *hashName) { 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, nullptr, nullptr, nullptr); Q_CHECK_PTR(key); auto *ctx = EVP_MD_CTX_new(); Q_CHECK_PTR(ctx); const auto *md = EVP_get_digestbyname(hashName); Q_CHECK_PTR(md); 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 { 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 buffer(buffer_size); while(const auto sz = plugin.readsome(&buffer.front(), buffer_size)) { rc = EVP_DigestVerifyUpdate(ctx, reinterpret_cast(buffer.data()), sz); if(rc != 1) { m_sigError = tr("Failed to compute signature (stage=update)"); return false; } } } // read signature into DigestVerifyFinal { 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 buffer(buffer_size); buffer.insert(buffer.begin(), std::istream_iterator(signature), std::istream_iterator()); signature.close(); rc = EVP_DigestVerifyFinal(ctx, buffer.data(), buffer_size); } if(rc != 1) { m_sigError = tr("Signature does not match"); return false; } return true; }