Browse Source

Add plugin signature verification policies

master
Aqua-sama 3 months ago
parent
commit
c5576c85c9
Signed by: Aqua-sama <aqua@iserlohn-fortress.net> GPG Key ID: 5378B8349C1D5ADA

+ 1
- 1
.gitignore View File

@@ -8,7 +8,7 @@ build*
8 8
 subprojects/
9 9
 lang/*.qm
10 10
 test/plugins.d
11
-
11
+publicKey.h
12 12
 .config
13 13
 .config.old
14 14
 

+ 1
- 1
Kconfig View File

@@ -10,7 +10,7 @@ endmenu
10 10
 source 'lib/configuration/Kconfig'
11 11
 
12 12
 # Plugin loading
13
-source 'lib/plugin/Kconfig'
13
+source 'lib/pluginloader/Kconfig'
14 14
 
15 15
 config USEPLASMA
16 16
     bool "Enable KDE Frameworks integration"

lib/plugin/Kconfig → lib/pluginloader/Kconfig View File

@@ -12,9 +12,6 @@ menu "Plugin Settings"
12 12
         config PLUGIN_SIGNATURE_IGNORED
13 13
             bool "Don't check plugin signatures"
14 14
 
15
-        config PLUGIN_SIGNATURE_NONFATAL
16
-            bool "Check signature validity, but always load plugins"
17
-
18 15
         config PLUGIN_SIGNATURE_CHECKED
19 16
             bool "Don't load plugins with invalid signatures"
20 17
 

+ 13
- 0
lib/pluginloader/meson.build View File

@@ -0,0 +1,13 @@
1
+dep_openssl = dependency('openssl')
2
+
3
+pluginloader_moc = mod_qt5.preprocess(
4
+    moc_headers: ['pluginloader.h'],
5
+    dependencies: dep_qt5
6
+)
7
+
8
+dep_pluginloader = declare_dependency(
9
+    include_directories: include_directories('.'),
10
+    link_with: static_library('plugin', 
11
+        ['pluginloader.cpp', pluginloader_moc],
12
+        dependencies: [dep_qt5, dep_openssl, dep_genheaders])
13
+)

src/plugin/pluginloader.cpp → lib/pluginloader/pluginloader.cpp View File

@@ -1,21 +1,28 @@
1
+/*
2
+ * This file is part of smolbote. It's copyrighted by the contributors recorded
3
+ * in the version control history of the file, available from its original
4
+ * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote
5
+ *
6
+ * SPDX-License-Identifier: GPL-3.0
7
+ */
8
+
1 9
 #include "pluginloader.h"
2 10
 #include <QFile>
3 11
 #include <openssl/evp.h>
4 12
 #include <openssl/pem.h>
5 13
 #include "publicKey.h"
6
-#include <spdlog/spdlog.h>
7 14
 
8
-PluginLoader::PluginLoader(const QString &fileName, QObject *parent)
15
+PluginLoader::PluginLoader(const QString &fileName, const VerifyState sigLevel, QObject *parent)
9 16
     : QPluginLoader(fileName, parent)
17
+    , requiredSignatureLevel(sigLevel)
10 18
 {
11 19
 }
12 20
 
13
-bool PluginLoader::verify(const char *hashName) const
21
+PluginLoader::VerifyState PluginLoader::verify(const char *hashName) const
14 22
 {
15 23
     const QString sigName = this->fileName() + ".sig";
16 24
     if(!QFile::exists(sigName)) {
17
-        spdlog::error("Signature does not exist: {}", qUtf8Printable(sigName));
18
-        return false;
25
+        return SignatureMissing;
19 26
     }
20 27
 
21 28
     auto *bio = BIO_new_mem_buf(publicKey_pem, publicKey_pem_len);
@@ -32,8 +39,7 @@ bool PluginLoader::verify(const char *hashName) const
32 39
 
33 40
     int rc = EVP_DigestVerifyInit(ctx, NULL, md, NULL, key);
34 41
     if(rc != 1) {
35
-        spdlog::error("DigestVerifyInit failed: %i", rc);
36
-        return false;
42
+        return SignatureMismatched;
37 43
     }
38 44
 
39 45
     // read plugin into DigestVerifyUpdate
@@ -48,7 +54,7 @@ bool PluginLoader::verify(const char *hashName) const
48 54
 
49 55
         rc = EVP_DigestVerifyUpdate(ctx, buf, read);
50 56
         if(rc != 1)
51
-            spdlog::error("DigestVerifyUpdate failed: %i", rc);
57
+            return SignatureComputeFailed;
52 58
     }
53 59
     delete buf;
54 60
     plugin.close();
@@ -68,10 +74,20 @@ bool PluginLoader::verify(const char *hashName) const
68 74
     delete sig;
69 75
 
70 76
     if(rc == 1)
71
-        return true;
77
+        return SignatureMatched;
72 78
     else {
73
-        spdlog::error("DigestVerifyFinal failed: %i", rc);
74
-        return false;
79
+        return SignatureMismatched;
75 80
     }
76 81
 }
82
+/*
83
+bool PluginLoader::load()
84
+{
85
+    if(signature == SignatureUnverified)
86
+        signature = this->verify();
77 87
 
88
+    if(signature > requiredSignatureLevel)
89
+        return QPluginLoader::load();
90
+    else
91
+        return false;
92
+}
93
+*/

+ 55
- 0
lib/pluginloader/pluginloader.h View File

@@ -0,0 +1,55 @@
1
+/*
2
+ * This file is part of smolbote. It's copyrighted by the contributors recorded
3
+ * in the version control history of the file, available from its original
4
+ * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote
5
+ *
6
+ * SPDX-License-Identifier: GPL-3.0
7
+ */
8
+
9
+#include <QPluginLoader>
10
+
11
+class PluginLoader : public QPluginLoader
12
+{
13
+    Q_OBJECT
14
+
15
+public:
16
+    enum VerifyState {
17
+        // uninitialized state
18
+        SignatureUnverified = -1,
19
+
20
+        // signature is optional, match is optional
21
+        SignatureCheckIfAvailable = 1,
22
+
23
+        SignatureComputeFailed = 2,     // error computing signature
24
+        SignatureMismatched = 3,        // signature does not match
25
+        
26
+        // signature is optional, match is required
27
+        SignatureMatchIfAvailable = 4,
28
+
29
+        SignatureMissing = 5,           // signature is not available
30
+
31
+        // signature required, match is required
32
+        SignatureMatchRequired = 10,
33
+
34
+        SignatureMatched = 20           // signature is matched
35
+    };
36
+
37
+    PluginLoader(const QString &fileName, const VerifyState sigLevel = SignatureMissing, QObject *parent = nullptr);
38
+    ~PluginLoader() = default;
39
+
40
+    QString errorString() const
41
+    {
42
+        if(signature < requiredSignatureLevel)
43
+            return QString("Required signature level: %2; Signature level: %3").arg(QString::number((int) requiredSignatureLevel), QString::number((int) signature));
44
+        else
45
+            return QPluginLoader::errorString();
46
+    }
47
+
48
+    VerifyState verify(const char *hashName = "SHA256") const;
49
+    //bool load();
50
+
51
+private:
52
+    const VerifyState requiredSignatureLevel;
53
+    VerifyState signature = SignatureUnverified;
54
+};
55
+

+ 0
- 1
linux/.config View File

@@ -76,7 +76,6 @@ CONFIG_USEPLUGINS=y
76 76
 # Plugin Settings
77 77
 #
78 78
 # CONFIG_PLUGIN_SIGNATURE_IGNORED is not set
79
-# CONFIG_PLUGIN_SIGNATURE_NONFATAL is not set
80 79
 CONFIG_PLUGIN_SIGNATURE_CHECKED=y
81 80
 # CONFIG_PLUGIN_SIGNATURE_ENFORCED is not set
82 81
 CONFIG_PLUGIN_SIGNATURE_HASH="SHA256"

+ 1
- 2
meson.build View File

@@ -26,8 +26,6 @@ dep_boost = dependency('boost', modules: ['program_options'])
26 26
 
27 27
 dep_spdlog = dependency('spdlog', fallback: ['spdlog', 'spdlog_dep'], version: '>=1.3.1')
28 28
 
29
-dep_openssl = dependency('openssl')
30
-
31 29
 optional_deps = []
32 30
 
33 31
 if get_option('Breakpad').enabled()
@@ -83,6 +81,7 @@ subdir('lib/addressbar')
83 81
 subdir('lib/bookmarks')
84 82
 subdir('lib/configuration')
85 83
 subdir('lib/downloads')
84
+subdir('lib/pluginloader')
86 85
 subdir('lib/urlfilter')
87 86
 subdir('lib/webprofile')
88 87
 

+ 9
- 4
src/browser.cpp View File

@@ -38,7 +38,7 @@
38 38
 #include "adblock/adblocklist.h"
39 39
 #include "hostlist/hostlist.h"
40 40
 #include <spdlog/spdlog.h>
41
-#include "plugin/pluginloader.h"
41
+#include <pluginloader.h>
42 42
 
43 43
 Browser::Browser(int &argc, char *argv[], bool allowSecondary)
44 44
     : SingleApplication(argc, argv, allowSecondary, SingleApplication::User | SingleApplication::SecondaryNotification | SingleApplication::ExcludeAppVersion)
@@ -151,9 +151,14 @@ QPluginLoader *Browser::addPlugin(const QString &path)
151 151
     if(path.isEmpty())
152 152
         return nullptr;
153 153
 
154
-    auto *loader = new PluginLoader(path, this);
155
-    spdlog::info("Verifying plugin: {}", loader->verify() ? "passed" : "failed");
156
-    loader->load();
154
+    auto *loader = new PluginLoader(path, PluginLoader::SignatureMatchIfAvailable, this);
155
+    const bool loaded = loader->load();
156
+    spdlog::info("Loading plugin [{}]: {}", qUtf8Printable(path), loaded ? "passed" : "failed");
157
+
158
+    if(!loaded) {
159
+        delete loader;
160
+        return nullptr;
161
+    }
157 162
 
158 163
     auto *info = new PluginInfo(loader);
159 164
     m_plugins.append(info);

+ 1
- 2
src/main.cpp View File

@@ -18,7 +18,7 @@
18 18
 #include <QFile>
19 19
 #include <QLibraryInfo>
20 20
 #include <QPluginLoader>
21
-#include "plugin/pluginloader.h"
21
+#include <pluginloader.h>
22 22
 #include <QTranslator>
23 23
 #include <memory>
24 24
 #include <plugininterface.h>
@@ -72,7 +72,6 @@ int main(int argc, char **argv)
72 72
     // Load plugins
73 73
     for(const QString &path : Util::files(config->value<QString>("plugins.path").value(), {"*.so", "*.dll"})) {
74 74
         auto *loader = new PluginLoader(path);
75
-        spdlog::info("Verifying plugin: {}", loader->verify() ? "passed" : "failed");
76 75
         const bool loaded = loader->load();
77 76
         spdlog::info("{} plugin {}", loaded ? "Loaded" : "Failed to load", qUtf8Printable(path));
78 77
 

+ 2
- 5
src/meson.build View File

@@ -1,7 +1,6 @@
1 1
 # poi
2 2
 poi_moc = mod_qt5.preprocess(
3 3
     moc_headers: ['browser.h',
4
-        'plugin/pluginloader.h',
5 4
         'mainwindow/mainwindow.h', 'mainwindow/menubar.h', 'mainwindow/widgets/dockwidget.h', 'mainwindow/widgets/menusearch.h', 'mainwindow/widgets/navigationbar.h', 'mainwindow/widgets/searchform.h',
6 5
         'session/savesessiondialog.h', 'session/sessiondialog.h', 'session/sessionform.h',
7 6
         'subwindow/subwindow.h', 'subwindow/tabwidget.h',
@@ -14,15 +13,13 @@ poi_moc = mod_qt5.preprocess(
14 13
 
15 14
 poi = executable(get_option('poiName'), install: true,
16 15
     cpp_args: ['-DQAPPLICATION_CLASS=QApplication'],
17
-    dependencies: [dep_qt5, dep_boost, dep_spdlog, dep_openssl, dep_SingleApplication, dep_genheaders, optional_deps,
18
-        dep_about, dep_addressbar, dep_bookmarks, dep_configuration, dep_downloads, dep_urlfilter, dep_webprofile],
16
+    dependencies: [dep_qt5, dep_boost, dep_spdlog, dep_SingleApplication, dep_genheaders, optional_deps,
17
+        dep_about, dep_addressbar, dep_bookmarks, dep_configuration, dep_downloads, dep_pluginloader, dep_urlfilter, dep_webprofile],
19 18
     include_directories: [include],
20 19
     sources: ['main.cpp', 'builtins.cpp', 'crashhandler.cpp', poi_moc,
21 20
     'browser.cpp',
22 21
     'util.cpp', 'util.h',
23 22
 
24
-    'plugin/pluginloader.cpp',
25
-
26 23
     'mainwindow/mainwindow.cpp',
27 24
     'mainwindow/menubar.cpp',
28 25
     'mainwindow/widgets/dockwidget.cpp',

+ 0
- 13
src/plugin/pluginloader.h View File

@@ -1,13 +0,0 @@
1
-#include <QPluginLoader>
2
-
3
-class PluginLoader : public QPluginLoader
4
-{
5
-    Q_OBJECT
6
-
7
-public:
8
-    PluginLoader(const QString &fileName, QObject *parent = nullptr);
9
-    ~PluginLoader() = default;
10
-
11
-    bool verify(const char *hashName = "SHA256") const;
12
-};
13
-

Loading…
Cancel
Save