diff options
| author | Aqua-sama <aqua@iserlohn-fortress.net> | 2020-01-26 23:14:53 +0200 | 
|---|---|---|
| committer | Aqua-sama <aqua@iserlohn-fortress.net> | 2020-01-27 15:58:31 +0200 | 
| commit | 0bf5450365934c39ed0bb480712adaab2fa54386 (patch) | |
| tree | 15b90e626ca7f29c9fa219addf17e9cf618b6496 /lib | |
| parent | Move compiler flags to meson.build from pkgbuild (diff) | |
| download | smolbote-0bf5450365934c39ed0bb480712adaab2fa54386.tar.xz | |
pluginloader: add test for PluginLoader::verify
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pluginloader/meson.build | 27 | ||||
| -rw-r--r-- | lib/pluginloader/pluginloader.cpp | 40 | ||||
| -rw-r--r-- | lib/pluginloader/pluginloader.h | 42 | ||||
| -rw-r--r-- | lib/pluginloader/test/pluginloader-sigmatch.cpp | 17 | ||||
| -rwxr-xr-x | lib/pluginloader/write-random.py | 15 | 
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)) + | 
