Plugins are currently simply perl code packed into a zip file.. We should add some form of standardized signing protocol to allow verification and authentication of source code.
I'm thinking something akin to Debians recommended practices: https://wiki.debian.org/Creating%20signed%20GitHub%20releases We could then verify signatures as part of the install process.
I one hundred percent agree with you, Martin. I figure Koha developers sign Koha plugins using a private GPG key, and then provide a public GPG key for *someone* to import into Koha. Personally, I'd prefer if the list of public GPG keys was maintained by a Linux sysadmin for maximum control, but I know that's potentially not useful for many target users of Koha plugins. (Maybe a compromise would be to have a web interface by default and then have an option to deactivate that and use a CLI tool instead for vendors?) In terms of specific interfaces... I'm going to look to see how Apt manages it in a user-friendly fashion (ie not requiring users to specify which key to use to verify which file). In any case, I think we have to have some system for signing and verifying plugins. From a vendor point of view, it would increase my confidence in the plugin system as a whole.
Preface: Apologies for the long post. It was my mental working through of possibilities for libraries for this functionality. Maybe it will be useful to someone else's thought process. Feel free to ignore and I'll write a shorter one after it with a suggestion. -- Oh right... gpg will handle that transparently if we just provide something like "gpg --verify plugin.sig plugin.kpz" or "gpg --decrypt plugin.kpz.sig --output plugin.kpz". Of course, the fun comes when shelling out to gpg from a web process... Some interesting conversation between Gregor Herrmann and Daniel Kahn Gillmor about this topic at https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=875124. They seem to suggest GnuPG::Interface but it still just shells out rather than using bindings. (A few years ago, I was interested in working on some Perl bindings for GPG, but just never found the time - quelle surprise.) On that note... we don't *have* to use GPG for signing. Although I don't really have any other obvious viable candidates. There's EdDSA (https://en.wikipedia.org/wiki/EdDSA#Software), but nothing there is standing out to me. Libgcrypt has signature support but I recall Crypt::GCrypt being terribly broken and it doesn't have signature support anyway. Although we could look at "python3-gpg" in Debian/Ubuntu which are official Python bindings for GPG using GPGME. But we couldn't use that in Starman and that would be a pain to setup. Maybe Crypt::OpenSSL::RSA which looks recent and seems to use bindings rather than shelling out. I see libcrypt-openssl-rsa-perl in Ubuntu 18.04. (Apparently Crypt::OpenSSL::RSA appears in some OCLC docs for working with Perl and Relais: https://help.oclc.org/Resource_Sharing/Relais_D2D/Authentication/Encryption) (Also kind of interesting looking at what Crypt::JWT uses for managing JWS algorithms: https://metacpan.org/pod/Crypt::JWT. As you can see, Crypt::OpenSSL::RSA shows up there again.) Oh that's interesting... for EdDSA it uses Crypt::PK::Ed25519, but Ubuntu 18.04 doesn't have Crypt::JWT or Crypt::PK::Ed25519. Oh actually... libcryptx-perl is available in Ubuntu 18.04 and Debian Stretch Backports...https://metacpan.org/pod/CryptX and https://packages.debian.org/search?keywords=libcryptx-perl No idea who Karel Miko is but that is amazing. Based on his LinkedIn, it looks like he's been doing security for quite a long time (and has maintained CryptX since 2013). https://metacpan.org/pod/Crypt::PK::RSA looks pretty interesting. And looking here https://metacpan.org/source/MIK/CryptX-0.068/CryptX.xs you can see it using the libtomcrypt headers (https://www.libtom.net/). Looks like libtomcrypt has 35 listed contributors (https://github.com/libtom/libtomcrypt/graphs/contributors) including Karel Miko... with most of the work starting in 2017...although apparently it was originally created by Tom St Denis (a Canadian from Ottawa) in 2001. So I'm guessing maybe not everything is shown in the Github. Seems like a pretty active project with a handful of developers working on it. Ooof... looks like there were some big dramas back in 2009 and Tom St Denis left the project and no one immediately took it up (https://groups.google.com/forum/#!msg/sci.crypt/Z7lVGM2wo2o/UfQpm0cdQRMJ). Obviously someone did resurrect it though. The Github history goes back to 2008/2009. Anyway that's just history. Seems like it's seen a fair bit of work since then, plus it's in every Linux distribution it seems. I feel like I've heard of libtomcrypt before in a project I was using... ahhh yes because dropbearssh uses libtomcrypt (which I compiled to run on my Android phone so I could use rsync on my phone using SSH). Anyway...
tl;dr Long story short... I'd suggest using libcrypt-openssl-rsa-perl or libcryptx-perl and probably going with a RSA or EdDSA key to do signatures.
I'm thinking something along these lines: https://ubuntu.com/tutorials/tutorial-how-to-verify-ubuntu Verify a metadata file or checksum file using a provider's public key (using one of the modules I've suggested). Then verify the plugin using a checksum in the metadata file or in the checksum file. I'm thinking signing the checksum file is probably the better way to go. And if we create a system preference to manage this, we can have it turned off by default (for backwards compatibility), but then more cautious parties (like vendors) can enable it. Essentially you'd need to verify a plugin during the installation process. -- I have many competing projects during my quarantine time, but I'm going to try and look at this tonight. It really shouldn't be that difficult, and I think it would be a huge benefit for the plugin system and Koha.
Oh interesting... we already have libcryptx-perl in the Koha Debian repository: http://debian.koha-community.org/koha/pool/main/libc/libcryptx-perl/ We have version 0.059 there which is older than what's in Stretch Backports, but that's probably OK...
Looks like both libcryptx-perl and libcrypt-openssl-rsa-perl are actually installed on koha-testing-docker... For the checksum, I'm using Digest::SHA which is a core module as well. Too easy...
Ahhh libcryptx-perl lives in /usr/lib/x86_64-linux-gnu/perl5/5.20, so it's a Jessie-only module. libcrypt-openssl-rsa-perl lives in /usr/lib/x86_64-linux-gnu/perl5/5.24, so it should be fine in Stretch. Ubuntu 18.04 is using Perl 5.26, which is fine for libcrypt-openssl-rsa-perl, since it's a system package, but no go for libcryptx-perl.
OK I've used openssl to generate a RSA private key and a public key, and create a signature for the KitchenSink KPZ (or more accurately a signature of a SHA256 digest of the KitchenSink KPZ). I've used Crypt::OpenSSL::RSA to load the public key and verify the signature against the KitchenSink KPZ file, and it's working very nicely on koha-testing-docker. Hurray! Next, I plan to great a plugin_keys table (or something like that) where admins can upload RSA public keys against a little descriptive name. Then, I'll add an upload option for the signature file. (I'll add a system preference to make the signature mandatory and default that preference to off for backwards compatibility.) Then, I iterate through the public keys to see if any of them return true. (The error reporting in Crypt::OpenSSL::RSA isn't brilliant. False is returned if the key is bad, false is returned if the file is bad, and false if the signature is bad. There's no way to differentiate between the failure states. That all being said, I suppose it doesn't matter too much. We can just tell users to review their saved keys, and double-check their source and that they're using the right signature for the right file.) I really thought I'd be able to work through my hunger but... going to have to eat.
Created attachment 104030 [details] Koha Plugin Signatures
Created attachment 104031 [details] Example Koha Plugin Developer Public Key
Created attachment 104032 [details] [review] Bug 24632: Verify Koha plugin signatures against trusted author public keys The concept is that Koha plugin authors will sign their plugins using their RSA private key, and they'll share their public key with Koha users/the public. Koha users will upload/import these public keys into Koha. When uploading plugins, Koha users will also be prompted to upload a signature file, which will be provided by Koha plugin authors. By default, signature verification will be optional. However, if you enable the system preference "RequirePluginSignatures", you will only be able to upload Koha plugins which have been signed by a trusted author (ie an author for whom you have stored a public key). This patch adds the plugin_keys table and a web UI to store trusted author public keys, adds the "RequirePluginSignatures" system preference to secure the upload process, and updates the plugin upload to verify signatures. Test Plan: 0) Apply patch 1) Download Example Koha Plugin Developer public key https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=104031 2) Download Kitchen Sink plugin signature https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=104030 3) Download version 2.1.39 of the Kitchen Sink plugin https://github.com/bywatersolutions/koha-plugin-kitchen-sink/releases/download/v2.1.39/koha-plugin-kitchen-sink-v2.1.39.kpz 4) Go to /cgi-bin/koha/plugins/plugins-keys.pl 5) Upload "Example Koha Plugin Developer public key" here with any "Name" you want 6) Go to /cgi-bin/koha/plugins/plugins-upload.pl 7) Upload Kitchen Sink plugin 8) Notice it uploaded without a signature. 9) Uninstall Kitchen Sink plugin 10) Go to systme preferences and enable "RequirePluginSignatures" 11) Go to /cgi-bin/koha/plugins/plugins-upload.pl 12) Upload Kitchen Sink plugin 13) Notice an error message saying upload failed 14) Go to /cgi-bin/koha/plugins/plugins-home.pl 15) Observe there is no uploaded plugin 16) Go to /cgi-bin/koha/plugins/plugins-upload.pl 17) Upload Kitchen Sink plugin 18) Upload Kitchen Sink plugin signature 19) Notice the plugin uploaded Advanced Test Plan: Instead of downloading the Koha Sink plugin signature and public key, try creating your own keys and signature. The below is just a quick example, and not necessarily the recommended process. Consider a larger key size. 1) openssl genrsa -des3 -out private.pem 2048 2) openssl rsa -in private.pem -outform PEM -pubout -out public.pem 3) openssl dgst -sha256 -sign private.pem -out koha-plugin-kitchen-sink-v2.1.39.sig koha-plugin-kitchen-sink-v2.1.39.kpz 4) Repeat normal test plan from step 4
Created attachment 104035 [details] [review] Bug 24632: Verify Koha plugin signatures against trusted author public keys The concept is that Koha plugin authors will sign their plugins using their RSA private key, and they'll share their public key with Koha users/the public. Koha users will upload/import these public keys into Koha. When uploading plugins, Koha users will also be prompted to upload a signature file, which will be provided by Koha plugin authors. By default, signature verification will be optional. However, if you enable the system preference "RequirePluginSignatures", you will only be able to upload Koha plugins which have been signed by a trusted author (ie an author for whom you have stored a public key). This patch adds the plugin_keys table and a web UI to store trusted author public keys, adds the "RequirePluginSignatures" system preference to secure the upload process, and updates the plugin upload to verify signatures. Test Plan: 0) Apply patch 1) Download Example Koha Plugin Developer public key https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=104031 2) Download Kitchen Sink plugin signature https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=104030 3) Download version 2.1.39 of the Kitchen Sink plugin https://github.com/bywatersolutions/koha-plugin-kitchen-sink/releases/download/v2.1.39/koha-plugin-kitchen-sink-v2.1.39.kpz 4) Go to /cgi-bin/koha/plugins/plugins-keys.pl 5) Upload "Example Koha Plugin Developer public key" here with any "Name" you want 6) Go to /cgi-bin/koha/plugins/plugins-upload.pl 7) Upload Kitchen Sink plugin 8) Notice it uploaded without a signature. 9) Uninstall Kitchen Sink plugin 10) Go to systme preferences and enable "RequirePluginSignatures" 11) Go to /cgi-bin/koha/plugins/plugins-upload.pl 12) Upload Kitchen Sink plugin 13) Notice an error message saying upload failed 14) Go to /cgi-bin/koha/plugins/plugins-home.pl 15) Observe there is no uploaded plugin 16) Go to /cgi-bin/koha/plugins/plugins-upload.pl 17) Upload Kitchen Sink plugin 18) Upload Kitchen Sink plugin signature 19) Notice the plugin uploaded Advanced Test Plan: Instead of downloading the Koha Sink plugin signature and public key, try creating your own keys and signature. The below is just a quick example, and not necessarily the recommended process. Consider a larger key size. 1) openssl genrsa -des3 -out private.pem 2048 2) openssl rsa -in private.pem -outform PEM -pubout -out public.pem 3) openssl dgst -sha256 -sign private.pem -out koha-plugin-kitchen-sink-v2.1.39.sig koha-plugin-kitchen-sink-v2.1.39.kpz 4) Repeat normal test plan from step 4 Signed-off-by: Holly <hc@interleaf.ie>
I noticed late yesterday that https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=23975 allows a person to fetch plugins directly from Github. I'll have to take a look at that code to see how it relates to what I've done here. I imagine it shouldn't be too difficult, especially if we use a standard naming convention for signature files.
You are assuming that an author who is trusted once is trusted for all the plugins they will write. This assumption is wrong IMO.
(In reply to Jonathan Druart from comment #15) > You are assuming that an author who is trusted once is trusted for all the > plugins they will write. This assumption is wrong IMO. This assumption is the same as the software package managers on Windows and Linux. I think it's a fair and conventional assumption to make. That being said, I agree with the content of what you're saying, which is why this feature needs to be paired with a whitelist where administrators can define which plugins should be allowed to be installed. That way administrators specify that only X authentic plugins from Y trusted authors can be installed. I'm planning to code the whitelist functionality too, but haven't had the time yet. In lieu of it, I think adding a signature system alone is better than the nothing that we have at the moment.
(In reply to Jonathan Druart from comment #15) > You are assuming that an author who is trusted once is trusted for all the > plugins they will write. This assumption is wrong IMO. I agree with David here.. this work is to provide a way of verifying the code is written by an author you trust.. not that this particular plugin is correct. As such, sharing a key is a fair and well-documented route that many systems already use.
I've rebased the patches (kohastructure.sql and plugins-home.tt, but there are a lot of QA script fails: FAIL Koha/Plugins/Key.pm OK critic OK forbidden patterns OK git manipulation OK pod FAIL pod coverage POD coverage was greater before, try perl -MPod::Coverage=PackageName -e666 OK spelling OK valid FAIL Koha/Plugins/Keys.pm OK critic FAIL forbidden patterns forbidden pattern: tab char (line 57) forbidden pattern: tab char (line 61) forbidden pattern: tab char (line 83) OK git manipulation OK pod FAIL pod coverage POD is missing for 'verify_plugin' OK spelling OK valid FAIL Koha/Schema/Result/PluginKey.pm OK critic OK forbidden patterns OK git manipulation OK pod FAIL pod coverage POD is missing for koha_object_class POD is missing for koha_objects_class OK spelling OK valid OK installer/data/mysql/kohastructure.sql OK boolean_vs_tinyint OK charset_collate OK git manipulation OK tinyint_has_boolean_flag OK installer/data/mysql/sysprefs.sql OK git manipulation OK semicolon OK sysprefs_order FAIL koha-tmpl/intranet-tmpl/prog/en/modules/plugins/plugins-home.tt OK filters FAIL forbidden patterns forbidden pattern: trailing space char (line 58) OK git manipulation OK js_in_body OK spelling OK tt_valid OK valid_template FAIL koha-tmpl/intranet-tmpl/prog/en/modules/plugins/plugins-keys.tt FAIL filters missing_filter at line 68 ( <li><a class="uninstall_plugin" href="/cgi-bin/koha/plugins/plugins-keys.pl?keyid=[% plugin_key.keyid %]&op=Delete"><i class="fa fa-trash fa-fw"></i> Delete</a></li>) FAIL forbidden patterns forbidden pattern: tab char (line 28) forbidden pattern: tab char (line 42) OK git manipulation OK js_in_body OK spelling OK tt_valid OK valid_template OK koha-tmpl/intranet-tmpl/prog/en/modules/plugins/plugins-upload.tt OK filters OK forbidden patterns OK git manipulation OK js_in_body OK spelling OK tt_valid OK valid_template FAIL plugins/plugins-keys.pl OK critic FAIL forbidden patterns forbidden pattern: Script permissions is authnotrequired => 0, it could be correct for an OPAC script if it is was you really want error (bug 24663) (line 42) OK git manipulation OK pod OK spelling OK valid Additional notes: 1) The 2 .perl files for database updates [c/sh]ould be combined. 2) Add comment before new table in kohastructure.sql 3) I wonder if the permission for the new page should not be a little stricter. Currently if you can use plugins, you can also access the page. I'd suggest: manage - Manage plugins ( install / uninstall ) This should then also affect the visibility of the buttons/links to the page from plugin home.
Thanks for taking the time to look at this one, Katrin. I appreciate it. I think for now I'm probably going to abandon this work, and focus instead on patches that limit users' ability to install plugins all together. That is, allow only administrators to install plugins, or allow only a pre-approved list of plugin options, or both. Hopefully my past work can serve as a bit of an example of what could be done in the future. For now, I don't think there will be enough uptake to warrant continuing working on it. But thanks again :)