-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Include digital signatures on project packages #1992
Comments
Nice example is here: |
👍 Security++ |
👍 |
Ooh. SyncThing also GPG signs their releases. MD5, while good for a lot of things, has been weakened enough that it shouldn't be used for making sure a package hasn't been intentionally hacked. I like the idea, but I suggest a stronger hash algorithm... SHA256, maybe. Even better, GPG sign them or encourage module maintainers to do so. |
Retitling this slightly. Like @jlfranklin, I think we can do better than md5, but if want to start with a simple hash and expand it out later, we can do that. Research over in #2018 led me to https://paragonie.com/blog/2016/10/guide-automatic-security-updates-for-php-developers, which included many, many excellent ideas. One of my favorite ideas is using private/public keys for digitally signing the packages. Backdrop's packager would sign the packages, which would then be stored on GitHub as they are now. Backdrop core would include the public key for validating the packages. The message of the package could even then be the md5 of the zip archive. So you'd both verify that the package came from a legitimate location, and that the zip file had not been tampered with in transit. For the public/private keys, the author recommends using libsodium (https://download.libsodium.org/doc/) which is built into PHP 7.2 and higher (if included in the compilation). But as we support many older versions of PHP and even new installations might not have it built in, the author amazingly created a bundleable version of libsodium as a pure PHP package that can be included as a .phar file (660KB): https://github.com/paragonie/sodium_compat Perhaps that's too much to handle all in one go, or perhaps not. If we're going through the work of updating the XML feeds on BackdropCMS.org to include an MD5, it could nearly as easily include a digital signature instead. |
If our packager can do that for them, then we should do that for them :) ...basically the plan that @quicksketch has laid out. |
I've been making progress on this functionality. Adding MD5 capability to the Project Release module is fairly trivial. So that shouldn't be difficult at all. Digital signing also doesn't appear to be too difficult, though we need to make some architecture decisions. Using the Sodium Compat library at https://github.com/paragonie/sodium_compat, the basics of signing are provided in the README.md file: <?php
require_once "/path/to/sodium_compat/autoload.php";
$alice_kp = sodium_crypto_sign_keypair();
$alice_sk = sodium_crypto_sign_secretkey($alice_kp);
$alice_pk = sodium_crypto_sign_publickey($alice_kp);
$message = 'This is a test message.';
$signature = sodium_crypto_sign_detached($message, $alice_sk);
if (sodium_crypto_sign_verify_detached($signature, $message, $alice_pk)) {
echo 'OK', PHP_EOL;
} else {
throw new Exception('Invalid signature');
} Applying this to Backdrop would mean the following:
Some additional thoughts:
In public static function sign(
string $message,
SignatureSecretKey $privateKey,
$encoding = Halite::ENCODE_BASE64URLSAFE
): string {
$signed = \sodium_crypto_sign_detached(
$message,
$privateKey->getRawKeyMaterial()
);
$encoder = Halite::chooseEncoder($encoding);
if ($encoder) {
return (string) $encoder($signed);
}
return (string) $signed;
} Where $message is an MD5 string, and $encoding is |
Sounds good. |
Sounds like you're reinventing SSL signing, minus the identity features. Where you have an offline key, SSL would use a CA key and cert. (It's easy enough to create a CA cert using OpenSSL.) The CA's key (private part) is kept offline, the cert itself (public part) is baked into Backdrop. A signing key is generated and that key/cert lives on backdropcms.org for signing packages. (Actually, it should live in a more secure signing server that has limited access to the internet, and only listens for signing requests from whitelisted sites like backdropcms.org.) The signing cert can be recreated if (when) it is compromised, and the individual package certs can carry the identity of the package and author(?) or signer(?). The date in the signed package's cert should match the release date of the module, and if it isn't refreshed in n years when the cert expires, the module should be considered abandoned. Separate signing certs can be generated based on characteristics of the module. For example, regular modules would get signed by the main cert, sandbox modules would be signed with a lower-grade cert. Using a certificate revocation list, modules with (>= serious) security releases have their signing certs revoked, as will modules that are considered abandoned before their cert expires. There will need to be some work done to verify the CA cert is the one that signed the package, but that code exists. The Backdrop project could then sell signing certs to major web shops or (cough) forks of the project as a way to generate some revenue. |
Well, I'm not reinventing SSL signing, I'm just using libsodium key-pair signing instead of SSL certificate signing. You bring up a good point though, we might be able use OpenSSL signed certificates instead of Sodium signing. I could see benefits and downsides: The existing Sodium functions seem to be made for this exact purpose, they're fairly trivial to implement, are (supposedly) quite secure, and are built into newer versions of PHP. On the downside, this technology is relatively new, and requires an backwards compatibility shim for older PHP versions. OpenSSL is available for all versions of PHP, but it requires that OpenSSL be installed on the host computer and PHP configured to use it correctly. I would expect that having PHP correctly configured and I'm also not clear on how an OpenSSL implementation would work. @jlfranklin could you attempt to stub out code you would expect to validate the signature of a downloaded package?
They would only need signing certs if they were redistributing their modules through another means than backdropcms.org, because the packager will already do the signing for everything in the contrib group. At this point we're just looking to make sure auto-updates come from a valid authority (backdropcms.org), so this validation only occurs when downloading a module, we wouldn't check anything for modules that already exist on disk (i.e. custom modules). Overall on the question of OpenSSL vs Sodium (or any other option), I'm fine with any of them as long as it's secure and relatively simple. I think we should choose whichever solution is going to be the least hassle for inexperienced end-users. |
I'd be happy to. Give me through the weekend. I'm not sure how much free time I have this week. |
I haven't tested all the pieces together, but I've put up a proof of concept against the backdropcms.org repository: backdrop-ops/backdropcms.org#456 For the time being I've just written it to use the sodium functions (though I have not included the sodium library itself yet). So far I've only tested creating a release and verifying that the MD5 is added correctly and that the MD5 + signature columns are added to the project_release table. Alternatively, we could put the signature as an attachment (asset) on the GitHub release, but it will make invalidating/regenerating signatures much easier if they're all stored centrally on backdropcms.org. |
I am sharing the same concern.
Sorry @jlfranklin, I am strongly against anything like this. What makes sense to me the way @quicksketch puts it, is that if a 3rd party is distributing their custom modules from another source, then perhaps we should be making profit out of that. Rationale:
my 2c |
My vote would be for using Sodium because 1) I like things that are easy, for learnability reasons. and 2) the shim may be useful for servers that don't have the Sodium module compiled with PHP, even after version 7.2, and 3) since we've already started going down this road this approach may also be the shortest route to the finish line. my .02 ;) |
I've worked through enough of the coding that I think I have a workable architecture for SSL-based signatures on modules. This post is pretty dense and technical. I don't recommend starting unless you have some time and spare cycles to devote to it. Before we start, I want to emphasize that SSL is about identity, not encryption. Encryption is a prerequisite for SSL, not a benefit. The same encryption algorithms used by SSL are also used by SSH. You could use an SSH tunnel to connect to a website securely, but you would have no assurance you're talking to the right web site. SSL provides the identity mechanism to know who you're talking to. Each SSL cert is a document that says, "I [insert signer's name here], hereby certify [insert subject's name here] is the owner of the private key matching the public key in this cert," and a digital signature that can be verified with the signer's public key. The cert contains the Common Name or CN of both the subject's name and the signer's name. (If you recognize CN from LDAP, it's because SSL and LDAP both derive from X.500 and share a lot of the same terminology.) SSL certs define a one-to-one, "A signs B" relationship. If you need multiple entities to sign a key, you need multiple certs. When I talk about creating certs below, I implicitly include the creation of a public-private key pair for the cert. With all that in mind, let's begin. As an overview, below is the certificate chain that I envision, with the CN of each cert in parenthesis. Root CA Cert (Backdrop Codesign CA) signs The Root CA Cert, Backdrop Codesign Intermediate cert, and any other CA certs are kept in The developer applies for his signing cert from the Backdrop Project. For the core code and core modules, the developer cert will have something like "Backdrop Core Team" as the CN, and be managed by the release team. Each module has a Now that the developer has his own signing cert, we're ready to sign a module. The signing process creates a module cert signed by the developer's cert. The name of the module and its version is the CN, and the The signing process reads the manifest file and concatenates the contents of each file named in order, finally adding the manifest itself to the end. This is the "data" that will be signed. The signing process then uses the private key associated with the module cert to sign the module "data". The signature -- a hash of the "data", encrypted with the signer's private key -- is written to a When Backdrop attempts to verify the signature, it reads the Multiple signatures can be in the Finally, a Codesign module can add signing information to the That's it. So far, it's about 400 lines of PHP. With proper docs and tests, I expect it to be around 1,000 lines total. I've run into a couple dead ends, because some of the OpenSSL functions were introduced later than I thought, some as recently as 7.2, and I wanted to make sure we had a solution that would work with PHP 5.x. Obviously, the code will need some thorough vetting, but I expect the hardest part will be the infrastructure to support it. |
I would have loved to get this into 1.12, but there is no way that is going to happen. Here is a quick update on my progress. To get this to work requires changes in multiple areas:
Changes to Project are already done. (See backdrop-contrib/project#25.) The I'm writing two contrib modules to ensure The And, of course, there will need to be a suite of tests written for all the different parts. |
Thanks for all your hard work and energy/time spent on this @jlfranklin 👍 Do we absolutely need to have a separate module for this? When we merged diff module in core (for use in the config diff in |
It implements |
Thanks for taking the time to respond @jlfranklin ...have not gotten my head around everything involved yet, but this helps. |
See also https://github.com/sd-backdrop/codesign_gnupg as the first functional signing module. |
Awesome @jlfranklin! I haven't checked in on this in a long time! It's great to see progress here.
Perhaps start separate, but if we use this on backdropcms.org we'll want it directly in project module. The situations where project module is not part of backdropcms.org are our secondary use-case, and it's already hard enough to manage with project module being separate from the main backdropcms.org repository. |
Wow, this looks awesome so far. Thanks for the hard work! |
Thanks @jlfranklin!!! I haven't yet had the time to review this. It sounds great though! I'll get to this when I can. |
I've been reviewing this one piece at a time. It's looks really good. So far I'm stuck in project module changes, but I'll get to reviewing the code_sign modules soon. |
I rerolled this patch against 1.x this morning. |
I've opened #3714 to track updates to the Installer module to check the digital signatures. |
Thanks @jlfranklin! With all the moving pieces between BackdropCMS.org, project module, and core, I don't think this is possible for 1.13.0, not your fault though, reviewing is where we got hung up here. Let's continue pushing forward on the infrastructure changes and getting the feeds themselves updated with including signatures in the short-term, and shoot for having them validated by core in 1.14.0. |
Which is the PR to be reviewed here? |
The PR for this issue is backdrop/backdrop#2449. I updated the summary to cross-link all the related issues as well. |
@jlfranklin I'm working on updating the PR for Project Support of Code Sign (backdrop-contrib/project#29). And found an area where the API may need to be updated. It looks like in order to test this I'd have to do the following:
If there's an API issue, we'd have to update 2 PRs and 2 projects in your personal account. To make this all easier, can we put all 4 modules into contrib (code_sign, code_sign_project, code_sign_gnupg, and code_sign_openssl)? For simplicity just putting them all in a single project (code_sign) would make changes across all 4 of them a lot easier. |
Yeah, a single code_sign project, with the rest of the things being submodules seems more appropriate. |
Code Sign itself needs to be in core, because Installer calls it to verify the packages are legit. |
I'd like to get it on BackdropCMS.org first so it can sign the packages and update the XML feed. But as it doesn't look like we'll likely put it in 1.14, I'd like to have it available so we can install it separately. It also gives us a good opportunity to change it without any repercussions. Though currently the only issue I've found is that the API for exposing signing profiles just has unnecessary hash sign prefixes: https://github.com/backdrop/backdrop/pull/2449/files#r317851694 |
...as also discussed during the last dev meeting, this should not have a release when moved to contrib. |
Hash signs removed in backdrop-contrib/project@b3ed711 The Contrib module (with sub-modules) for Code Sign is now pushed up to https://github.com/backdrop-contrib/code_sign, also with the hash signs removed. |
I'm taking this out of the 1.15.0 milestone, as today is feature freeze and this is still not ready (mostly my fault I know). I'll continue to take this forward when I can but if there are any volunteers who are interested I'm happy to turn over the work. |
I propose to implement MD5 checksum for each packaged project.
It can be provided as a part of the title.
We need to use it via project installer to make sure that package is not hacked and replaced.
Advocates: @jlfranklin @quicksketch
Weekly update?
Proof of concept by quicksketch: backdrop-ops/backdropcms.org#456Initial core PR by @jlfranklin: backdrop/backdrop#2449
Other related issues that also need to be done:
The text was updated successfully, but these errors were encountered: