{ "info": { "author": "Ryan Kelly", "author_email": "rfk@cloudmatrix.com.au", "bugtrack_url": null, "classifiers": [], "description": "signedimp: signed imports for verified loading of python modules\n=================================================================\n\n\nThis module implements an import hook for verifying Python modules before they\nare loaded, by means of cryptographically-signed hashes. It is compatible with\nPEP 302 and designed to complement the code-signing functionality of your host\nOS (e.g. Microsoft Authenticode, Apple OSX Code Signing) which may be able to\nverify the Python executable itself but not the code that is dynamically loaded\nat runtime.\n\nIt will mostly be useful for frozen Python applications, or other situations\nwhere code is not expected to change. It will be almost useless with a\nstandard Python interpreter.\n\nIf you're just after a black-box solution, you could try one of the following\nfunction calls to sign your app with a new randomly-generated key::\n\n signedimp.tools.sign_py2exe_app(path_to_app_dir)\n signedimp.tools.sign_py2app_bundle(path_to_app_dir)\n signedimp.tools.sign_cxfreeze_app(path_to_app_dir)\n\nThese functions modify a frozen Python application so that it verifies the\nintegrity of its modules before they are loaded, using a one-time key generated\njust for that application.\n\nBut really, you should read on to understand exactly what's going on. There\nare plenty of caveats to be had.\n\n\nEnabling Signed Imports\n-----------------------\n\nTo enable signed imports, you need to create a SignedImportManager with the\nappropriate cryptographic keys and install it into the import machinery::\n\n from signedimp import SignedImportManager, RSAKey\n\n key = RSAKey(modulus,pub_exponent)\n mgr = SignedImportManager([key])\n mgr.install()\n\nFrom this point on, all requests to import a module will be checked against\nsigned manifest files before being allow to proceed. If a module cannot be\nverified then the import will fail.\n\nVerification is performed in coopertion with the existing import machinery,\nusing the optional loader method get_data(). It works with at least the \ndefault import machinery and the zipimport module; if you have custom import\nhooks that don't offer this method, or that don't conform to the standard\nfile layout for python imports, they will will not be usable with signedimp.\n\n\nKeys\n----\n\nCurrently signedimp uses RSA keys for its digital signatures, along with the\n\"Probabilistic Signature Scheme\" padding mechanism. To generate a new key\nyou will need PyCrypto installed, and to do the following::\n\n from signedimp.crypto.rsa import RSAKey\n key = RSAKey.generate()\n pubkey = key.get_public_key()\n\nStore this key somewhere safe, you'll need it to sign files. The simplest way\nis using the \"save_to_file\" method::\n\n with open(\"mykeyfile\",\"wb\") as f:\n key.save_to_file(f,\"mypassword\")\n\nTo retreive the key in e.g. your build scripts, do something like this::\n\n with open(\"mykeyfile\",\"rb\") as f:\n key = RSAKey.load_from_file(f,getpass())\n\nYou'll also need to embed the public key somewhere in your final executable\nso it's available for verifying imports. The functions in signedimp.tools will\ndo this for you - if you're writing you own scheme you can either pickle it, or\nembed its repr() somewhere in your source code.\n\n\nManifests\n---------\n\nTo verify imports, each entry on sys.path must contain a manifest file, which\ncontains a cryptographic hash for each module and is signed by one or more\nprivate keys. This file is called \"signedimp-manifest.txt\" and it will be\nrequested from each import loader using the get_data() method - in practice\nthis means that the file must exist in the root of each directory and each\nzipfile listed on sys.path.\n\nThe manifest is a simple text file. It begins with zero or more lines giving\na key fingerprint followed by a signature using that key; these are separated\nfrom the hash data by a blank line. It then contains a hash type identifier\nand one line for each module hash. Here's a short example::\n\n ----\n key1fingerprint b64-encoded-signature1\n key2fingerprint b64-encoded-signature2\n\n md5\n 76f3f13442c26fd4f1c709c7b03c6b76 os.pyc\n f56dbc5ee6774e857a7ef07accdbd19b hashlib.pyc\n 43b74fc5d2acb6b4e417f4feff06dd81 some/data/file.txt\n ----\n \nThe format of the fingerprint and signature depend on the types of key being\nused, and should be treated as ASCII blobs.\n\nTo create a manifest file you will need a key object that includes the private\nkey data. You can then use the functions in the \"tools\" submodule::\n\n key = RSAKey(modulus,pub_exponent,priv_exponent)\n\n signedimp.tools.sign_directory(\"some/dir/on/sys/path\",key)\n signedimp.tools.sign_zipfile(\"some/zipfile/on/sys/path.zip\",key)\n\n\nBootstrapping\n-------------\n\nClearly there is a serious bootstrapping issue when using this module - while\nwe can verify imports one this module is loaded, how do we verify the import of\nthis module itself? To be of any use, it must be incorporated as part of a\nsigned executable. There are several options:\n\n * include signedimp as a \"frozen\" module in the Python interpreter itself,\n by mucking with the PyImport_FrozenModules pointer.\n\n * include signedimp in a zipfile appended to the executable, and put the\n executable itself as the first item on sys.path.\n\n * use the signedimp.tools.get_bootstrap_code() function to obtain code that\n can be included verbatim in your startup script, and embed the startup\n script in the executable.\n\nSince the bootstrapping code can't perform any imports, everything (even the\ncryptographic primitives!) is implemented in pure Python by default. It is\nthus rather slow. If you're able to securely bundle e.g. hashlib or PyCrypto\nin the executable itself, import them *before* installing the signed import\nmanager so that it knows they are safe to use.\n\nOf course, the first thing the import manager does once installed is try to\nimport these modules and speed up imports for the rest of the process.\n\nA word of caution - most freezer programs (e.g. py2exe or bbfreeze) execute\ntheir own startup scripts before running the user-supplied script, and these\nstartup scripts often import common modules such as \"os\". You'll either need\nto hack the frozen exe to run the signedimp bootstrapping code first, or\nsecurely bundle these modules into the executable itself.\n\nSo far I've worked out the necessary incantations for signing py2exe, py2app\nand cxfreeze applications, and there are helper functions in \"signedimp.tools\"\nthat will do it for you.\n\nI don't belive it's possible to sign a bbfreeze application without patching\nbbfreeze itself. Since bbfreeze always sets sys.path to the library.zip and\nthe application dir, there is no way to bundle the bootstrapping code into\nthe executable itself.\n\n\nCaveats\n-------\n\nAll of the usual crypto caveats apply here. I'm not a security expert. The\nsystem is only a safe as your private key, as the signature on the main python\nexecutable, and as the operating system it's run on. In addition, there are\nsome specific caveats for this module based on the way it works.\n\nThis module operates by wrapping the existing import machinery. To check the\nhash of a module, it asks the appropriate loader object for the code of that\nmodule, verifies the hash, then gives the loader the OK to import it. It's\nquite likely that the loader will re-read the data from disk when loading the\nmodule, so there is a brief window in which it could be replaced by malicious\ncode. I don't see any way to avoid this short of replacing all the existing\nimport machinery, which I'm not going to do.\n\nAs mentioned above, this module is useless if you load it from an untrusted\nsource. You will need to sign your actual executable and you will need to\nsomehow bundle some signedimp bootstrapping code into it. See the section\non \"bootstrapping\" for more details.\n\nYou must also be careful not to import anything before you have installed the\nsigned import manager. (One exception is the \"sys\" module, which should always\nbe built into the executable itself and so safe to import.)\n\nFinally, you may have noticated that I'm going against all sensible crypto\nadvice and rolling my own scheme from basic primitives such as RSA and SHA1.\nIt would be much better to depend on a third-party crypto library like keyczar,\nhowever:\n\n * I want the verification code to be runnable as pure python without\n any third-party imports, to make it as easy to bootstrap as possible.\n\n * I've copied the signature scheme directly from PKCS#1 and it's broadly\n the same as that used by keyczar etc. This is a very simple and well\n understood signing protocol.\n\n * The signing code is supposed to be run offline, in a controlled setting\n with controlled inputs, so the risk of e.g. timing attacks is small.\n\n * The verifying code can't leak any info about the private key because\n it simply doesn't have any, so it can be as slow and sloppy and clunky\n as needed.\n\nI am of course open to negotiation and expert advice on any of these points.\n\nYou have been warned.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/cloudmatrix/signedimp/", "keywords": "code-signing verification import hooks", "license": "BSD", "maintainer": null, "maintainer_email": null, "name": "signedimp", "package_url": "https://pypi.org/project/signedimp/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/signedimp/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://github.com/cloudmatrix/signedimp/" }, "release_url": "https://pypi.org/project/signedimp/0.3.2/", "requires_dist": null, "requires_python": null, "summary": "signed imports for verified loading of python modules", "version": "0.3.2" }, "last_serial": 799534, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "63758adb06d88edc8e838e599afa6789", "sha256": "ad5d0671a6bf29336c4fff24f560ef4f6416be6bbb92a5440738c07d7377f80c" }, "downloads": -1, "filename": "signedimp-0.1.0.tar.gz", "has_sig": false, "md5_digest": "63758adb06d88edc8e838e599afa6789", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30921, "upload_time": "2010-07-10T09:04:06", "url": "https://files.pythonhosted.org/packages/b6/b3/efc7b6eadc72663653ea12f6d3c534161a9705cdb075270445b6e6b60193/signedimp-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "c612c3008c8042409785b2c699661d30", "sha256": "6b5b0d8b4b8374fd7e0c76fb0acafccd67134817df0cd592cfee3aa389ccf019" }, "downloads": -1, "filename": "signedimp-0.1.1.tar.gz", "has_sig": false, "md5_digest": "c612c3008c8042409785b2c699661d30", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 34313, "upload_time": "2010-07-13T04:41:38", "url": "https://files.pythonhosted.org/packages/bd/38/1895ea6a575a1c81cbba6cb460a598009173dae7a9718dcd00fc8a6d10f3/signedimp-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "7c058c03e6c91043170445c1bbd340c8", "sha256": "7671fc8c713b2471424377e336249989c864dda68bfa7a1ee039445c85fb3e0a" }, "downloads": -1, "filename": "signedimp-0.1.2.tar.gz", "has_sig": false, "md5_digest": "7c058c03e6c91043170445c1bbd340c8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 36623, "upload_time": "2010-07-14T01:57:19", "url": "https://files.pythonhosted.org/packages/7e/54/a9d6e6f884c4e4d51255aedfd974f3849391550d863502a0af8609df99a2/signedimp-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "7c4250f4465dc21a5daf240f0f5e3998", "sha256": "33ddbd16c545cc1c52af6bef400def109679b03a5ab528f6adebf322321033ad" }, "downloads": -1, "filename": "signedimp-0.1.3.tar.gz", "has_sig": false, "md5_digest": "7c4250f4465dc21a5daf240f0f5e3998", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 37745, "upload_time": "2010-07-16T16:03:51", "url": "https://files.pythonhosted.org/packages/dd/0e/a74e4c6780293de892dda2afc7163a21b69f9b8deee21a09fcf75fc6f2da/signedimp-0.1.3.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "d25de7db32b9f3ba8ff53a342ade620c", "sha256": "e94618a64906154e8202148102864c97dc4de8442ca8f885048dd09502e392b1" }, "downloads": -1, "filename": "signedimp-0.1.4.tar.gz", "has_sig": false, "md5_digest": "d25de7db32b9f3ba8ff53a342ade620c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 38192, "upload_time": "2010-07-21T08:32:30", "url": "https://files.pythonhosted.org/packages/45/3e/4620bcccc3b70111c75d1c322496e5f9be80ac5e2bec8d5b97ea66d18141/signedimp-0.1.4.tar.gz" } ], "0.1.5": [ { "comment_text": "", "digests": { "md5": "e28c46a1889b4cde546da4196412abd7", "sha256": "ceb07e3a0c8b3cb954a0f4e368aa21eef1751aca75effd4d7e17cf16e8888d12" }, "downloads": -1, "filename": "signedimp-0.1.5.tar.gz", "has_sig": false, "md5_digest": "e28c46a1889b4cde546da4196412abd7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 40483, "upload_time": "2010-07-30T15:09:03", "url": "https://files.pythonhosted.org/packages/e9/52/58888e1960a7f361173ba116e92491be4a90b2a9cfc2ae90eba7fab90fe5/signedimp-0.1.5.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "e43a54ca920bf63c5914d6038e9724f9", "sha256": "67c076f731faacf874bde15f9774eebba338b97f66d5f532a7a858198b6f7364" }, "downloads": -1, "filename": "signedimp-0.2.0.tar.gz", "has_sig": false, "md5_digest": "e43a54ca920bf63c5914d6038e9724f9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 42547, "upload_time": "2010-08-10T12:00:30", "url": "https://files.pythonhosted.org/packages/75/46/10661ed86b594e94a73dcd5676bf92a5536389e8df9eb954e0588ab83603/signedimp-0.2.0.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "21c817447d889d760bf7d3f7a554e8a8", "sha256": "01a4af8a4455637e296fb98ba69570ae093e68680cd3bcd87ed4493eeb840a15" }, "downloads": -1, "filename": "signedimp-0.3.0.tar.gz", "has_sig": false, "md5_digest": "21c817447d889d760bf7d3f7a554e8a8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 44525, "upload_time": "2010-09-04T13:02:07", "url": "https://files.pythonhosted.org/packages/7d/23/dad2cac6b85bfb981290defc8ad0a4821abd4f1163e0346fed6d9bd66fb0/signedimp-0.3.0.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "7c2ba2bde287cc85d45f9af44d72a19a", "sha256": "07f4a7a43dccdd8de52b735ff87f4d37587d7f5f891127382d1c1656e872cedc" }, "downloads": -1, "filename": "signedimp-0.3.1.tar.gz", "has_sig": false, "md5_digest": "7c2ba2bde287cc85d45f9af44d72a19a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 44852, "upload_time": "2010-12-01T23:58:03", "url": "https://files.pythonhosted.org/packages/2d/40/863d5e4a5f0030392c0e1c5ab541839f7fed3071ee4343a038f9a2b6f83e/signedimp-0.3.1.tar.gz" } ], "0.3.2": [ { "comment_text": "", "digests": { "md5": "7f78ebf99727a83abe25c1c750025975", "sha256": "aa76350818f4f2a6b2f3011b9119b415da0b8712ca7a151ed2ac4747f3e774b1" }, "downloads": -1, "filename": "signedimp-0.3.2.tar.gz", "has_sig": false, "md5_digest": "7f78ebf99727a83abe25c1c750025975", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 44907, "upload_time": "2010-12-28T09:45:57", "url": "https://files.pythonhosted.org/packages/86/ac/781d9ff4fa6ba764eb69622b4ad098a5cdd0e3ee6095787af37daa789c21/signedimp-0.3.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "7f78ebf99727a83abe25c1c750025975", "sha256": "aa76350818f4f2a6b2f3011b9119b415da0b8712ca7a151ed2ac4747f3e774b1" }, "downloads": -1, "filename": "signedimp-0.3.2.tar.gz", "has_sig": false, "md5_digest": "7f78ebf99727a83abe25c1c750025975", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 44907, "upload_time": "2010-12-28T09:45:57", "url": "https://files.pythonhosted.org/packages/86/ac/781d9ff4fa6ba764eb69622b4ad098a5cdd0e3ee6095787af37daa789c21/signedimp-0.3.2.tar.gz" } ] }