aboutsummaryrefslogtreecommitdiff
path: root/lib/pluginloader
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2020-01-26 23:14:53 +0200
committerAqua-sama <aqua@iserlohn-fortress.net>2020-01-27 15:58:31 +0200
commit0bf5450365934c39ed0bb480712adaab2fa54386 (patch)
tree15b90e626ca7f29c9fa219addf17e9cf618b6496 /lib/pluginloader
parentMove compiler flags to meson.build from pkgbuild (diff)
downloadsmolbote-0bf5450365934c39ed0bb480712adaab2fa54386.tar.xz
pluginloader: add test for PluginLoader::verify
Diffstat (limited to 'lib/pluginloader')
-rw-r--r--lib/pluginloader/meson.build27
-rw-r--r--lib/pluginloader/pluginloader.cpp40
-rw-r--r--lib/pluginloader/pluginloader.h42
-rw-r--r--lib/pluginloader/test/pluginloader-sigmatch.cpp17
-rwxr-xr-xlib/pluginloader/write-random.py15
5 files changed, 95 insertions, 46 deletions
diff --git a/lib/pluginloader/meson.build b/lib/pluginloader/meson.build
index cbca725..534f385 100644
--- a/lib/pluginloader/meson.build
+++ b/lib/pluginloader/meson.build
@@ -25,3 +25,30 @@ dep_pluginloader = declare_dependency(
dependencies: [dep_qt5, dependency('openssl', required: true)])
)
+openssl = find_program('openssl', required: true)
+
+# generate a test file that would be signed
+signedfile_dat = custom_target('signedfile.dat',
+ input: 'write-random.py',
+ output: 'signedfile.dat',
+ command: [ python3, '@INPUT@', '--output=@OUTPUT@' ]
+)
+# sign test file
+signedfile_sig = custom_target('signedfile.dat.sig',
+ input: signedfile_dat,
+ output: 'signedfile.dat.sig',
+ command: [ openssl, 'dgst', '-sha256', '-sign', private_pem, '-out', '@OUTPUT@', '@INPUT@' ]
+)
+
+signedfile_idep = declare_dependency(sources: [ signedfile_dat, signedfile_sig ])
+
+pluginloader_sigmatch = executable('pluginloader-sigmatch',
+ sources: [ 'test/pluginloader-sigmatch.cpp' ],
+ dependencies: [ dep_qt5, dep_gtest, dep_pluginloader, signedfile_idep ]
+)
+
+test('pluginloader: signature matching', pluginloader_sigmatch,
+ env: environment({ 'SIGNEDFILE' : 'signedfile.dat' }),
+ workdir: meson.current_build_dir()
+)
+
diff --git a/lib/pluginloader/pluginloader.cpp b/lib/pluginloader/pluginloader.cpp
index c8358bf..e5c4b89 100644
--- a/lib/pluginloader/pluginloader.cpp
+++ b/lib/pluginloader/pluginloader.cpp
@@ -12,17 +12,21 @@
#include <openssl/pem.h>
#include "publicKey.h"
-PluginLoader::PluginLoader(const QString &fileName, const VerifyState sigLevel, QObject *parent)
+PluginLoader::PluginLoader(const QString &fileName, PluginLoader::SignatureState state, QObject *parent)
: QPluginLoader(fileName, parent)
- , requiredSignatureLevel(sigLevel)
+ , m_state(state)
{
}
-PluginLoader::VerifyState PluginLoader::verify(const char *hashName) const
+bool PluginLoader::verify(const char *hashName)
{
const QString sigName = this->fileName() + ".sig";
if(!QFile::exists(sigName)) {
- return SignatureMissing;
+ if(m_state.ignored || m_state.checked)
+ return true;
+
+ m_sigError = tr("A signature is required, but none was found.");
+ return false;
}
auto *bio = BIO_new_mem_buf(publicKey_pem, publicKey_pem_len);
@@ -39,7 +43,8 @@ PluginLoader::VerifyState PluginLoader::verify(const char *hashName) const
int rc = EVP_DigestVerifyInit(ctx, NULL, md, NULL, key);
if(rc != 1) {
- return SignatureMismatched;
+ m_sigError = tr("Failed to compute signature (stage=init)");
+ return false;
}
// read plugin into DigestVerifyUpdate
@@ -53,8 +58,10 @@ PluginLoader::VerifyState PluginLoader::verify(const char *hashName) const
len -= read;
rc = EVP_DigestVerifyUpdate(ctx, buf, read);
- if(rc != 1)
- return SignatureComputeFailed;
+ if(rc != 1) {
+ m_sigError = tr("Failed to compute signature (staga=update)");
+ return false;
+ }
}
delete[] buf;
plugin.close();
@@ -74,20 +81,13 @@ PluginLoader::VerifyState PluginLoader::verify(const char *hashName) const
delete sig;
if(rc == 1)
- return SignatureMatched;
+ return true;
else {
- return SignatureMismatched;
- }
-}
-/*
-bool PluginLoader::load()
-{
- if(signature == SignatureUnverified)
- signature = this->verify();
+ if(m_state.ignored)
+ return true;
- if(signature > requiredSignatureLevel)
- return QPluginLoader::load();
- else
+ m_sigError = tr("Signature does not match");
return false;
+ }
}
-*/
+
diff --git a/lib/pluginloader/pluginloader.h b/lib/pluginloader/pluginloader.h
index 48be61d..b602f5b 100644
--- a/lib/pluginloader/pluginloader.h
+++ b/lib/pluginloader/pluginloader.h
@@ -13,45 +13,35 @@ class PluginLoader : public QPluginLoader
Q_OBJECT
public:
- enum VerifyState {
- // uninitialized state
- SignatureUnverified = -1,
- // signature is optional, match is optional
- SignatureCheckIfAvailable = 1,
+ struct SignatureState {
+ bool ignored; // always ignore signature
+ bool checked; // check if available
+ bool enforced; // always check
- SignatureComputeFailed = 2, // error computing signature
- SignatureMismatched = 3, // signature does not match
-
- // signature is optional, match is required
- SignatureMatchIfAvailable = 4,
-
- SignatureMissing = 5, // signature is not available
-
- // signature required, match is required
- SignatureMatchRequired = 10,
-
- SignatureMatched = 20 // signature is matched
+ SignatureState(bool ignore, bool check, bool enforce) {
+ ignored = ignore;
+ checked = check;
+ enforced = enforce;
+ }
};
- PluginLoader(const QString &fileName, const VerifyState sigLevel = SignatureMissing, QObject *parent = nullptr);
+ PluginLoader(const QString &fileName, SignatureState state, QObject *parent = nullptr);
~PluginLoader() = default;
QString errorString() const
{
- if(signature < requiredSignatureLevel)
- return QString("Required signature level: %2; Signature level: %3").arg(
- QString::number(static_cast<int>(requiredSignatureLevel)),
- QString::number(static_cast<int>(signature)));
+ if(!m_sigError.isEmpty())
+ return m_sigError;
else
return QPluginLoader::errorString();
}
- VerifyState verify(const char *hashName = "SHA256") const;
- //bool load();
+ bool verify(const char *hashName = "SHA256");
private:
- const VerifyState requiredSignatureLevel;
- VerifyState signature = SignatureUnverified;
+ const SignatureState m_state;
+
+ QString m_sigError;
};
diff --git a/lib/pluginloader/test/pluginloader-sigmatch.cpp b/lib/pluginloader/test/pluginloader-sigmatch.cpp
new file mode 100644
index 0000000..2e5a1ff
--- /dev/null
+++ b/lib/pluginloader/test/pluginloader-sigmatch.cpp
@@ -0,0 +1,17 @@
+#include "pluginloader.h"
+#include <gtest/gtest.h>
+
+PluginLoader *loader = nullptr;
+
+TEST(PluginLoader, SignatureMatcher) {
+ EXPECT_TRUE(loader->verify());
+}
+
+int main(int argc, char **argv)
+{
+ const PluginLoader::SignatureState state(false, true, false);
+ loader = new PluginLoader(qgetenv("SIGNEDFILE"), state);
+
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/lib/pluginloader/write-random.py b/lib/pluginloader/write-random.py
new file mode 100755
index 0000000..6834f3b
--- /dev/null
+++ b/lib/pluginloader/write-random.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python3
+
+import argparse
+import os
+import sys
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Generate file containing random data')
+ parser.add_argument('--output', type=argparse.FileType('wb'), default=sys.stdout, help='Output file')
+ parser.add_argument('--length', type=int, default=256, help='Length of file')
+
+ args=parser.parse_args()
+
+ args.output.write(os.urandom(args.length))
+