12

I'd like to (PGP/GPG) sign python code. Yes, I have read this and many other sites that talk about protecting and obfuscating python code - this all is not what I want. I DON'T want to obfuscate code. I want customers and users to see the code, they could modify code, copy it and make derivative work, I'd like to have the software under the GPLv3. But I want to have plugins that are "signed", so they can be kind of trusted during execution.

Is this possible in Python? Can I import a library after checking its gpg signing? What would be easy: check the gpg signing of a file, and then load it via import, else raise an exception. But this only would be possible for single-file-imports, not directory python modules.

It is clear that, if the customer changes the GPG key in the program, or deletes some lines himself in the checking algorithm, all is gone - but this is not the problem. He could do anything he wants - but this would be silly. What he wants is trustworthiness. I want to let him add a third party plugin by copying it into a "plugins" directory, and have the program check the plugin for "trustworthiness" - and then import it. (So he could run plugins that are not signed, but with his own risk.)

Community
  • 1
  • 1
nerdoc
  • 1,044
  • 10
  • 28
  • 2
    I believe you should carefully check [the `import` system](http://docs.python.org/3/reference/import.html) of python since it allows you to write custom [import hooks](http://www.python.org/dev/peps/pep-0302/). What I'd do: provide the plug-ins as `zip` files containing the modules/packages *and* the signature. Then the import would first check the signature, and if it is correct it could decompress the archive into a temporary directory and import the modules from there ([or directly from the `zip`](http://docs.python.org/2/library/zipimport.html)). Users can unzip the archive and modify it. – Bakuriu Jan 14 '14 at 19:48
  • @Bakuriu great comment and that should be an answer. – Eugene Mayevski 'Callback Jan 15 '14 at 08:58
  • That's what I thought earlier, too, using a zip file. This would be one of my features: download a signed zip/other "plugin package" file from a dedicated server, check gpg, unpack it. Ok, so the "installation" into the dedicated "plugins" dir should be done by the software too, then the problem would be solved if I understood correctly. Being admin on the system circumvents this by changing the code as root anyway. And I did not know about import hooks, thanks very much. – nerdoc Jan 15 '14 at 19:15
  • oh, and @Bakuriu, could you post that as "answer" as well, so I can mark it as right answer? If you want you can just more or less copy'n'paste the text from your comment above. – nerdoc Jan 15 '14 at 19:16

2 Answers2

9

Python's import mechanism already provide all the tools necessary to achieve what you want. You can install different kinds of import hooks in order to support what you want.

In particular you'll probably find convenient to install a meta path hook that searches for "signed modules" and returns a Loader that is able to perform the imports from this signed format.

A very simple and convenient format for your signed plug-ins would be a zip archive containing:

  1. The code of the plug-in in the form of modules/packages
  2. A PGP signature of the above code

In this way:

  • Your loader should unpack the zip, and check the signature. If it matches then you can safely load the plug-in, if it doesn't match you should ask the user to trust the plug-in (or not and abort)
  • If the user wants to modify the plug-in it can simply unpack the zip archive and modify it as he wishes.
  • Imports from zip archives are already implemented in the zipimport module. This means that you don't have to rewrite a loader from scratch.

Actually if you want to reduce the code for the hooks to the minimum you'd simply need to verify the signature and then add the path to the zip archive into sys.path, since python already handles imports from zip archive even without explicitly using zipimport.

Using this design you just have to install these hooks and then you can import the plug-in as if they were normal modules and the verification etc. will be done automatically.

Bakuriu
  • 98,325
  • 22
  • 197
  • 231
3

I know this is an old post, but we've developed a new solution. We were confronted with the same challenge -- to distribute python source code, but to prevent hackers from tampering with the code. The solution we developed was to create a custom loader for our application using signet http://jamercee.github.io/signet/.

What signet does is scans your script and it's dependencies creating sha1 hashes. It embeds these hashes into a custom loader which you deliver to your customer with your script. Your customers run the loader which re-verifies the hashes before it transfers control to your script for normal execution. If there's been tampering it emits an error message, and refuses to run the tampered code.

Signet is multiplatform and runs on windows, unix, linux, freebsd, etc... If you deploy to windows, the loader building process can even apply your company code certificate for 100% verification of your code. It also does PE verification.

The code is fully open source including the c++ source code to the default loader template. You can extend the loader to do additional verifications and even take actions if it detects code tampering (like undoing the tampering...).

user590028
  • 11,364
  • 3
  • 40
  • 57
  • 2
    Hm. SHA1 is a cryptographic checksum, no signing. Anyone could build the same checksum and place it into the software, right? You have to ship the checksum WITH your "plugin" - but what does an attacker prevent to modify the plugin code, and rebuild the checksum? A Checksum only prevents accidental code change (by download error e.g.) - but not tampering. What would be needed there is an asymetric key like GPG. The software knows about the public key, and the plugin is signed using the private one. This can't be changed by an attacker. Linux packages (rpm/deb) are signed this way. – nerdoc Jul 31 '14 at 17:09
  • Code signing prevents tampering of the loader (on windows), which is included with Signet (http://jamercee.github.io/signet/signet.command.sign_code.html). The loader invokes WinVerifyTrust function to confirm the loader binary signature matches the signers signature before invoking the script. There are no universal solutions to this on Linux yet (but we're still looking). – user590028 Jul 31 '14 at 18:46
  • Might be worth a check to this link as well http://jamercee.github.io/signet/index.html#code-signing – user590028 Jul 31 '14 at 18:55
  • Hm. An "universal" solution would be public key signing. I need this to run in Linux... – nerdoc Jul 31 '14 at 20:04
  • To the best of my knowledge, there no 'cert store' on linux. Without it there's no way to authenticate the chain of trust. A hacker could strip your cert, insert their own self-signed cert (even fake your org name), and it would fool everyone. The closest we've found is signelf (http://sourceforge.net/projects/signelf/), but without a means to authenticate the chain, it's not any better than just relying on code hashes. Of course, if you know a way around this -- I'd love to know about it so we could fold this into signet ASAP ! – user590028 Jul 31 '14 at 20:33
  • Not entirely. You are right that there is a chain of trust. If you don't trust the OS (cert storage), you can't trust anyone ;-). Under Linux e.g. Debian packages are signed with a GPG private debian key. As long as the hacker doesn't have root access and changes the public debian key in the local system, the signed package can be trusted more than anything else IMHO. By calling WinVerifyTrust, you trust the OS. But You can't be sure that noone hacked the Windows system and bypassed the WinVerifyTrust function, right? – nerdoc Aug 03 '14 at 17:31
  • Have a look at http://www.securitytracker.com/id?1026906 (I just googled 1 minute to find this). So GPG keys ARE secure, IF you can trust the OS. If not, you can't do ANYTHING to keep it safe IMHO. – nerdoc Aug 03 '14 at 17:31
  • What I mean is: I don't think you can really prevent installing malicious python plugins into YOUR system if YOU want to install a malicious plugin. What I try to achieve is being sure to load a signed and correct plugin IF I HAVE A *CLEAN* SYSTEM (TM). ;-) And this should go perfectly ok with e.g. PGP signing. If my Python interpreter is hacked, everything here is senseless. – nerdoc Aug 03 '14 at 17:34
  • There are a couple of comments to make -- first regarding WinVerifyTrust bypass -- that notice is regarding the Windows loader. It does not apply to your own code. Meaning, the signet loader cannot be bypassed (unless someone could hack the binary to branch OVER the call to WinVerifyTrust. Certainly not impossible -- but it's a major hack. And that theoretical hack would be intimately tied to the specific build. A new compile-build-deploy would make the previous hack obsolete (because code offsets would change) and that means it would require a complete new hack. – user590028 Aug 04 '14 at 13:27
  • Regarding the use of PGP and code signing. I think it's interesting, but would make it very difficult to deploy to a large installation base of customers and users. Each user would need to have a copy of your key installed in their keyring. And if you wanted to run the code as root, you'd need the software publishers key in the root keyring as well. If the publisher needed to refresh their key, every user would need to update the keyring. The nice thing about windows is they take of this for you with the certificate store and chain of trust. – user590028 Aug 04 '14 at 13:30
  • fyi -- I hope you don't think I'm being argumentative. Just trying to share my thoughts, and compare with yours. – user590028 Aug 04 '14 at 18:53
  • While this may be a really good way on Windows to go, it is not at all cross-platform (that's what I am looking for). Debian has this "chain of trust" as well - the keyring is included in the system. And nothing is complicated to maintain a package that contains your public key, signed by Debian's or Ubuntu's maintainers. RedHat/Suse the same. Windows gives you a nice tool, but just for Windows (as always) - this is why I don't use Windows much - because of not being flexible in that direction. If you once use Windows (here: WinVerifyTrust), you need to stay there for a while. Mac too. – nerdoc Aug 04 '14 at 18:54
  • There is nothing wrong with this. I just need a cross platform (=Python) code. But I despite that will have a look at signet! Thanks anyway! – nerdoc Aug 04 '14 at 18:55
  • No, relax ;-) - I really appreciate the communication here! I'm just doing the same... Thanks! – nerdoc Aug 04 '14 at 19:26