1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
/*
* 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 <QFile>
#include <filesystem>
#include <fstream>
#include <openssl/evp.h>
#include <openssl/pem.h>
bool PluginLoader::verify(const char *hashName)
{
const std::filesystem::path plugin_path(fileName().toStdString());
if(!std::filesystem::exists(plugin_path)) {
m_sigError = tr("Plugin doesn't exist.");
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<char> buffer(buffer_size);
std::size_t sz = 0;
while(true) {
sz = static_cast<std::size_t>(plugin.readsome(&buffer.front(), buffer_size));
if(sz <= 0)
break;
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;
}
}
}
// 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<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;
}
|