commit a4fc36eabb00bb47114b8379319d3897a63427ac Author: Isis Lovecruft isis@torproject.org Date: Sun Feb 22 10:58:04 2015 +0000
Add crypto.initializeGnuPG() function.
This switches BridgeDB to using python-gnupg rather than pygpgme.
* FIXES #10385 https://bugs.torproject.org/10385 --- lib/bridgedb/crypto.py | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+)
diff --git a/lib/bridgedb/crypto.py b/lib/bridgedb/crypto.py index a16e45a..6bb5c7d 100644 --- a/lib/bridgedb/crypto.py +++ b/lib/bridgedb/crypto.py @@ -41,6 +41,7 @@ Module Overview from __future__ import absolute_import from __future__ import unicode_literals
+import gnupg import hashlib import hmac import io @@ -273,14 +274,92 @@ def removePKCS1Padding(message):
return unpadded
+def initializeGnuPG(config): + """Initialize a GnuPG interface and test our configured keys. + + .. note:: This function uses python-gnupg_. + + :type config: :class:`bridgedb.persistent.Conf` + :param config: The loaded config file. + :rtype: 2-tuple + :returns: If ``EMAIL_GPG_SIGNING_ENABLED`` isn't ``True``, or we couldn't + initialize GnuPG and make a successful test signature with the + specified key, then a 2-tuple of ``None`` is returned. Otherwise, the + first item in the tuple is a :class:`gnupg.GPG` interface_ with the + GnuPG homedir set to the ``EMAIL_GPG_HOMEDIR`` option and the signing + key specified by the ``EMAIL_GPG_SIGNING_KEY_FINGERPRINT`` option in + bridgedb.conf set as the default key. The second item in the tuple is + a signing function with the passphrase (as specified in either + ``EMAIL_GPG_PASSPHRASE`` or ``EMAIL_GPG_PASSPHRASE_FILE``) already + set. + + .. _python-gnupg: https://pypi.python.org/pypi/gnupg/ + .. _interface: https://python-gnupg.readthedocs.org/en/latest/gnupg.html#gnupg-module + """ + ret = (None, None)
+ if not config.EMAIL_GPG_SIGNING_ENABLED: + return ret
+ homedir = config.EMAIL_GPG_HOMEDIR + primary = config.EMAIL_GPG_PRIMARY_KEY_FINGERPRINT + passphrase = config.EMAIL_GPG_PASSPHRASE + passFile = config.EMAIL_GPG_PASSPHRASE_FILE
+ logging.info("Using %s as our GnuPG home directory..." % homedir) + gpg = gnupg.GPG(homedir=homedir) + logging.info("Initialized GnuPG interface using %s binary with version %s." + % (gpg.binary, gpg.binary_version))
+ primarySK = None + primaryPK = None + secrets = gpg.list_keys(secret=True) + publics = gpg.list_keys()
+ if not secrets: + logging.warn("No secret keys found in %s!" % gpg.secring) + return ret
+ primarySK = filter(lambda key: key['fingerprint'] == primary, secrets) + primaryPK = filter(lambda key: key['fingerprint'] == primary, publics)
+ if primarySK and primaryPK: + logging.info("Found GnuPG primary key with fingerprint: %s" % primary) + for sub in primaryPK[0]['subkeys']: + logging.info(" Subkey: %s Usage: %s" % (sub[0], sub[1].upper())) + else: + logging.warn("GnuPG key %s could not be found in %s!" % (primary, gpg.secring)) + return ret + + if passphrase: + logging.info("Read GnuPG passphrase from config.") + elif passFile: + try: + with open(passFile) as fh: + passphrase = fh.read() + except (IOError, OSError): + logging.error("Could not open GnuPG passphrase file: %s!" % passFile) + else: + logging.info("Read GnuPG passphrase from file: %s" % passFile)
+ def gpgSignMessage(message): + """Sign **message** with the default key specified by + ``EMAIL_GPG_PRIMARY_KEY_FINGERPRINT``. + + :param str message: A message to sign. + :rtype: str or ``None``. + :returns: A string containing the clearsigned message, or ``None`` if + the signing failed. + """ + sig = gpg.sign(message, default_key=primary, passphrase=passphrase) + if sig and sig.data: + return sig.data + + logging.debug("Testing signature created with GnuPG key...") + sig = gpgSignMessage("Testing 1 2 3") + if sig: + logging.info("Test signature with GnuPG key %s okay:\n%s" % (primary, sig)) + return (gpg, gpgSignMessage)
class SSLVerifyingContextFactory(ssl.CertificateOptions):
tor-commits@lists.torproject.org