[tor-commits] [bridgedb/develop] Remove old GPGME-based GnuPG functions from bridgedb.crypto.

isis at torproject.org isis at torproject.org
Tue Feb 24 07:03:14 UTC 2015


commit a87eb73576cd23a9891c69448e44a38732cd963f
Author: Isis Lovecruft <isis at torproject.org>
Date:   Sun Feb 22 10:52:15 2015 +0000

    Remove old GPGME-based GnuPG functions from bridgedb.crypto.
    
     * REMOVE PythonicGpgmeError.
     * REMOVE LessCrypticGPGMEError.
     * REMOVE _createGPGMEErrorInterpreters.
     * REMOVE gpgmeErrorTranslations.
     * REMOVE getGPGContext.
     * REMOVE gpgSignMessage.
     * REMOVE all associated tests.
---
 lib/bridgedb/crypto.py           |  208 --------------------------------------
 lib/bridgedb/test/test_crypto.py |  202 ------------------------------------
 2 files changed, 410 deletions(-)

diff --git a/lib/bridgedb/crypto.py b/lib/bridgedb/crypto.py
index 724d649..a16e45a 100644
--- a/lib/bridgedb/crypto.py
+++ b/lib/bridgedb/crypto.py
@@ -41,7 +41,6 @@ Module Overview
 from __future__ import absolute_import
 from __future__ import unicode_literals
 
-import gpgme
 import hashlib
 import hmac
 import io
@@ -93,46 +92,6 @@ class PKCS1PaddingError(Exception):
 class RSAKeyGenerationError(Exception):
     """Raised when there was an error creating an RSA keypair."""
 
-class PythonicGpgmeError(Exception):
-    """Replacement for ``gpgme.GpgmeError`` with understandable error info."""
-
-class LessCrypticGPGMEError(Exception):
-    """Holds interpreted info on source/type of a ``gpgme.GpgmeError``."""
-
-    def __init__(self, gpgmeError, *args):
-        self.interpretCrypticGPGMEError(gpgmeError)
-        super(LessCrypticGPGMEError, self).__init__(self.message)
-
-    def interpretCrypticGPGMEError(self, gpgmeError):
-        """Set our ``message`` attribute with a decoded explanation of the
-        GPGME error code received.
-
-        :type gpgmeError: ``gpgme.GpgmeError``
-        :param gpgmeError: An exception raised by the gpgme_ module.
-
-        .. _gpgme: https://bazaar.launchpad.net/~jamesh/pygpgme/trunk/view/head:/src/pygpgme-error.c
-        """
-        try:
-            errorSource, errorCode, errorMessage = gpgmeError.args
-        except (AttributeError, ValueError):
-            self.message = "Could not get error code from gpgme.GpgmeError!"
-            return
-
-        if errorCode and errorSource:
-            try:
-                sources = gpgmeErrorTranslations[str(errorSource)]
-            except KeyError:
-                sources = ['UNKNOWN']
-            sources = ', '.join(sources).strip(',')
-
-            try:
-                names = gpgmeErrorTranslations[str(errorCode)]
-            except KeyError:
-                names = ['UNKNOWN']
-            names = ', '.join(names).strip(',')
-
-            self.message = "GpgmeError: {0} stemming from {1}: '{2}'""".format(
-                names, sources, str(errorMessage))
 
 def writeKeyToFile(key, filename):
     """Write **key** to **filename**, with ``0400`` permissions.
@@ -314,181 +273,14 @@ def removePKCS1Padding(message):
 
     return unpadded
 
-def _createGPGMEErrorInterpreters():
-    """Create a mapping of GPGME ERRNOs ←→ human-readable error names/causes.
 
-    This function is called automatically when :mod:`this module
-    <bridgedb.crypto>` is loaded. The resulting dictionary mapping is stored
-    as :attr:`~bridgedb.crypto.gpgmeErrorTranslations`, and is used by
-    :exc:`~bridgedb.crypto.LessCrypticGPGMEError`.
 
-    :returns: A dict of::
-          {str(ERRNO): [ERRORNAME, ANOTHER_ERRORNAME, …],
-           …,
-           str(ERRORNAME): str(ERRNO),
-           …}
-        for all known error numbers and error names/causes.
-    """
-    errorDict = {}
-    errorAttrs = []
-
-    if gpgme is not None:
-        errorAttrs = dir(gpgme)
-
-    for attr in errorAttrs:
-        if attr.startswith('ERR'):
-            errorName = attr
-            errorCode = getattr(gpgme, attr, None)
-            if errorCode is not None:
-                try:
-                    allErrorNames = errorDict[str(errorCode)]
-                except KeyError:
-                    allErrorNames = []
-                allErrorNames.append(str(errorName))
-
-                errorDict.update({str(errorCode): allErrorNames})
-                errorDict.update({str(errorName): str(errorCode)})
-
-    return errorDict
-
-#: This is a dictionary which holds a translation of GPGME ERRNOs ←→ all known
-#: names/causes for that ERRNO, and vice versa. It is created automatically,
-#: via the :func:`_createGPGMEErrorInterpreters` function, when this module is
-#: loaded so that :exc:`LessCrypticGPGMEError` can use it to display
-#: human-readable information about why GPGME borked itself on something.
-gpgmeErrorTranslations = _createGPGMEErrorInterpreters()
-
-def getGPGContext(cfg):
-    """Import a key from a file and initialise a context for GnuPG operations.
-
-    The key should not be protected by a passphrase, and should have the
-    signing flag enabled.
-
-    :type cfg: :class:`bridgedb.persistent.Conf`
-    :param cfg: The loaded config file.
-    :rtype: :class:`gpgme.Context` or None
-    :returns: A GPGME context with the signers initialized by the keyfile
-        specified by the option EMAIL_GPG_SIGNING_KEY in bridgedb.conf, or
-        None if the option was not enabled, or was unable to initialize.
-    """
-    try:
-        # must have enabled signing and specified a key file
-        if not cfg.EMAIL_GPG_SIGNING_ENABLED or not cfg.EMAIL_GPG_SIGNING_KEY:
-            return None
-    except AttributeError:
-        return None
 
-    keyfile = None
-    ctx = gpgme.Context()
 
-    try:
-        binary = GPGME_CONTEXT_BINARY[0]
-    except Exception:
-        # Setting this to ``None`` will cause libgpgme to "use the default
-        # binary", according their docs:
-        binary = None
 
-    try:
-        homedir = os.path.abspath(GPGME_CONTEXT_HOMEDIR)
-        logging.debug("Setting GPG homedir to %r" % homedir)
-        if not os.path.isdir(homedir):
-            os.makedirs(homedir)
-        # This is done to ensure that we don't ever use keys in the process
-        # owner's $GNUPGHOME directory, see:
-        # http://www.gnupg.org/documentation/manuals/gpgme/Crypto-Engine.html#Crypto-Engine
-        ctx.set_engine_info(gpgme.PROTOCOL_OpenPGP, binary, homedir)
-
-        logging.debug("Opening GPG keyfile %s..." % cfg.EMAIL_GPG_SIGNING_KEY)
-        keyfile = open(cfg.EMAIL_GPG_SIGNING_KEY)
-        key = ctx.import_(keyfile)
-
-        if not len(key.imports) > 0:
-            logging.debug("Unexpected result from gpgme.Context.import_(): %r"
-                          % key)
-            raise PythonicGpgmeError("Could not import GnuPG key from file %r"
-                                     % cfg.EMAIL_GPG_SIGNING_KEY)
-
-        fingerprint = key.imports[0][0]
-        subkeyFingerprints = []
-        # For some reason, if we don't do it exactly like this, we can get
-        # signatures for *any* key in the current process owner's keyring
-        # file:
-        bridgedbKey = ctx.get_key(fingerprint)
-        bridgedbUID = bridgedbKey.uids[0].uid
-        logging.info("GnuPG key imported: %s" % bridgedbUID)
-        logging.info("       Fingerprint: %s" % fingerprint)
-        for subkey in bridgedbKey.subkeys:
-            logging.info("Subkey fingerprint: %s" % subkey.fpr)
-            subkeyFingerprints.append(subkey.fpr)
-
-        ctx.armor = True
-        ctx.signers = (bridgedbKey,)
-
-        logging.debug("Testing signature created with GnuPG key...")
-        signatureText, sigs = gpgSignMessage(ctx, "Testing 1 2 3")
-
-        if not len(sigs) == 1:
-            raise PythonicGpgmeError("Testing couldn't produce a signature "\
-                                     "with GnuPG key: %s" % fingerprint)
-
-        sigFingerprint = sigs[0].fpr
-        if sigFingerprint in subkeyFingerprints:
-            logging.info("GPG signatures will use subkey with fingerprint: %s"
-                         % sigFingerprint)
-        else:
-            if sigFingerprint != fingerprint:
-                raise PythonicGpgmeError(
-                    "Test sig fingerprint '%s' not from any appropriate key!"
-                    % sigFingerprint)
-
-    except (IOError, OSError) as error:
-        logging.debug(error)
-        logging.error("Could not open or read from GnuPG key file %r!"
-                      % cfg.EMAIL_GPG_SIGNING_KEY)
-        ctx = None
-    except gpgme.GpgmeError as error:
-        lessCryptic = LessCrypticGPGMEError(error)
-        logging.error(lessCryptic)
-        ctx = None
-    except PythonicGpgmeError as error:
-        logging.error(error)
-        ctx = None
-    finally:
-        if keyfile and not keyfile.closed:
-            keyfile.close()
-
-    return ctx
-
-def gpgSignMessage(gpgmeCtx, messageString, mode=None):
-    """Sign a **messageString** with a GPGME context.
-
-    :param gpgmeCtx: A ``gpgme.Context`` initialised with the appropriate
-        settings.
-    :param str messageString: The message to sign.
-    :param mode: The signing mode. (default: ``gpgme.SIG_MODE_CLEAR``)
-    :rtype: tuple
-    :returns: A 2-tuple of ``(signature, list)``, where:
-        * ``signature`` is the ascii-armored signature text.
-        * ``list`` is a list of ``gpgme.NewSignature``s.
-
-    .. warning:: The returned signature text and list *may* be empty, if no
-        signature was created.
-    """
-    if not mode:
-        mode = gpgme.SIG_MODE_CLEAR
 
-    if NEW_BUFFER_INTERFACE:
-        msgFile = io.BytesIO(buffer(messageString))
-        sigFile = io.BytesIO()
-    else:
-        msgFile = io.StringIO(unicode(messageString))
-        sigFile = io.StringIO()
 
-    sigList = gpgmeCtx.sign(msgFile, sigFile, mode)
-    sigFile.seek(0)
-    signature = sigFile.read()
 
-    return (signature, sigList)
 
 
 class SSLVerifyingContextFactory(ssl.CertificateOptions):
diff --git a/lib/bridgedb/test/test_crypto.py b/lib/bridgedb/test/test_crypto.py
index 801a369..da93f07 100644
--- a/lib/bridgedb/test/test_crypto.py
+++ b/lib/bridgedb/test/test_crypto.py
@@ -15,7 +15,6 @@ from __future__ import print_function
 from __future__ import unicode_literals
 
 import base64
-import gpgme
 import io
 import logging
 import math
@@ -24,7 +23,6 @@ import shutil
 
 import OpenSSL
 
-
 from twisted.internet import defer
 from twisted.trial import unittest
 from twisted.test.proto_helpers import StringTransport
@@ -286,143 +284,6 @@ class RemovePKCS1PaddingTests(unittest.TestCase):
                           self.blob)
 
 
-class LessCrypticGPGMEErrorTests(unittest.TestCase):
-    """Unittests for :class:`bridgedb.crypto.LessCrypticGPGMEError`."""
-
-    def test_error1(self):
-        """libgpgme will raise an error when given an io.StringIO for the
-        message or sigfile.
-        """
-        message = io.StringIO(unicode(self.id()))
-        sigfile = io.StringIO()
-
-        lessCryptic = None
-        ctx = gpgme.Context()
-
-        try:
-            ctx.sign(message, sigfile)
-        except gpgme.GpgmeError as error:
-            lessCryptic = crypto.LessCrypticGPGMEError(error)
-
-        self.assertTrue('Invalid argument' in lessCryptic.message)
-
-    def test_noGpgmeErrorArgs(self):
-        """A gpgme.GpgmeError() without error code args should result in a
-        'Could not get error code from gpgme.GpgmeError!' message.
-        """
-        error = gpgme.GpgmeError()
-        lessCryptic = crypto.LessCrypticGPGMEError(error)
-        self.assertEqual(lessCryptic.message,
-                         'Could not get error code from gpgme.GpgmeError!')
-
-    def test_unknownErrorSource(self):
-        """A gpgme.GpgmeError() without a recognisable error source should say
-        that the error source is 'UNKNOWN'.
-        """
-        msg = "These numbers make more sense than libgpgme's error codes."
-        error = gpgme.GpgmeError(math.pi, math.e, msg)
-        lessCryptic = crypto.LessCrypticGPGMEError(error)
-        self.assertSubstring('UNKNOWN', lessCryptic.message)
-        self.assertSubstring(msg, lessCryptic.message)
-
-    def test_unknownErrorCode(self):
-        """A gpgme.GpgmeError() without a recognisable error code should say
-        that the error code is 'UNKNOWN'.
-        """
-        msg = "These numbers make more sense than libgpgme's error codes."
-        error = gpgme.GpgmeError(math.pi, math.e, msg)
-        lessCryptic = crypto.LessCrypticGPGMEError(error)
-        self.assertSubstring('UNKNOWN', lessCryptic.message)
-        self.assertSubstring(msg, lessCryptic.message)
-
-
-class GPGContextTests(unittest.TestCase):
-    """Tests for :func:`bridgedb.crypto.getGPGContext`."""
-
-    timeout = 15
-
-    @fileCheckDecorator
-    def doCopyFile(self, src, dst, description=None):
-        shutil.copy(src, dst)
-
-    def removeRundir(self):
-        """Remove the rundir from the _trial_tmp directory."""
-        if os.path.isdir(self.runDir):
-            shutil.rmtree(self.runDir)
-
-    def makeBadKey(self):
-        """Make a bad keyfile and set its path in our config."""
-        keyfile = os.path.join(self.runDir, 'badkey.asc')
-        with open(keyfile, 'w') as badkey:
-            badkey.write(str('NO PASARAN, DEATH CAKES!'))
-            badkey.flush()
-        self.setKey(keyfile)
-
-    def enableSigning(self, enable=True):
-        """Enable or disable the config setting for email signing."""
-        setattr(self.config, 'EMAIL_GPG_SIGNING_ENABLED', enable)
-
-    def setKey(self, keyfile=''):
-        """Set the config keyfile path to **keyfile**."""
-        setattr(self.config, 'EMAIL_GPG_SIGNING_KEY', keyfile)
-
-    def setUp(self):
-        here          = os.getcwd()
-        topDir        = here.rstrip('_trial_temp')
-        self.runDir   = os.path.join(here, 'rundir')
-        self.gpgFile  = os.path.join(topDir, 'gnupghome', 'TESTING.subkeys.sec')
-        self.gpgExpr  = os.path.join(topDir, 'gnupghome',
-                                     'TESTING.subkeys.sec.EXPIRED-2013-09-11')
-
-        if not os.path.isdir(self.runDir):
-            os.makedirs(self.runDir)
-
-        self.config = Conf()
-        self.enableSigning()
-        self.addCleanup(self.enableSigning)
-        self.addCleanup(self.removeRundir)
-
-    def test_getGPGContext_good_keyfile(self):
-        """Test EmailServer.getGPGContext() with a good key filename."""
-        self.setKey(self.gpgFile)
-        ctx = crypto.getGPGContext(self.config)
-        self.assertIsInstance(ctx, gpgme.Context)
-
-    def test_getGPGContext_missing_keyfile(self):
-        """Test EmailServer.getGPGContext() with a missing key filename."""
-        self.setKey('missing-keyfile.asc')
-        ctx = crypto.getGPGContext(self.config)
-        self.assertTrue(ctx is None)
-
-    def test_getGPGContext_bad_keyfile(self):
-        """Test EmailServer.getGPGContext() with a missing key filename."""
-        self.makeBadKey()
-        ctx = crypto.getGPGContext(self.config)
-        self.assertTrue(ctx is None)
-
-    def test_getGPGContext_expired_keyfile(self):
-        """getGPGContext() with an expired key should return None."""
-        self.setKey(self.gpgExpr)
-        ctx = crypto.getGPGContext(self.config)
-        self.assertTrue(ctx is None)
-
-    def test_getGPGContext_signing_disabled(self):
-        """getGPGContext() with signing disabled should return None."""
-        self.setKey(self.gpgFile)
-        self.enableSigning(False)
-        ctx = crypto.getGPGContext(self.config)
-        self.assertIsNone(ctx)
-
-    def test_getGPGContext_config_signing_missing(self):
-        """getGPGContext() with a missing/unset 'EMAIL_GPG_SIGNING_ENABLED'
-        config line should return None.
-        """
-        self.setKey(self.gpgFile)
-        delattr(self.config, 'EMAIL_GPG_SIGNING_ENABLED')
-        ctx = crypto.getGPGContext(self.config)
-        self.assertIsNone(ctx)
-
-
 class SSLVerifyingContextFactoryTests(unittest.TestCase,
                                       txtagent.FakeReactorAndConnectMixin):
     """Tests for :class:`bridgedb.crypto.SSLVerifyingContextFactory`."""
@@ -503,66 +364,3 @@ class SSLVerifyingContextFactoryTests(unittest.TestCase,
         contextFactory = crypto.SSLVerifyingContextFactory(self.url)
         self.assertIsInstance(contextFactory.getContext(),
                               OpenSSL.SSL.Context)
-
-
-class GetGPGContextTest(unittest.TestCase):
-    """Unittests for :func:`bridgedb.crypto.getGPGContext`."""
-
-    timeout = 15
-
-    @fileCheckDecorator
-    def doCopyFile(self, src, dst, description=None):
-        shutil.copy(src, dst)
-
-    def removeRundir(self):
-        if os.path.isdir(self.runDir):
-            shutil.rmtree(self.runDir)
-
-    def makeBadKey(self):
-        self.setKey(self.badKeyfile)
-
-    def setKey(self, keyfile=''):
-        setattr(self.config, 'EMAIL_GPG_SIGNING_KEY', keyfile)
-
-    def setUp(self):
-        here          = os.getcwd()
-        topDir        = here.rstrip('_trial_temp')
-        self.runDir   = os.path.join(here, 'rundir')
-        self.gpgMoved = os.path.join(here, 'TESTING.subkeys.sec')
-        self.gpgFile  = os.path.join(topDir, 'gnupghome',
-                                     'TESTING.subkeys.sec')
-
-        if not os.path.isdir(self.runDir):
-            os.makedirs(self.runDir)
-
-        self.badKeyfile = os.path.join(here, 'badkey.asc')
-        with open(self.badKeyfile, 'w') as badkey:
-            badkey.write('NO PASARAN, DEATH CAKES!')
-            badkey.flush()
-
-        self.doCopyFile(self.gpgFile, self.gpgMoved, "GnuPG test keyfile")
-
-        self.config = Conf()
-        setattr(self.config, 'EMAIL_GPG_SIGNING_ENABLED', True)
-        setattr(self.config, 'EMAIL_GPG_SIGNING_KEY',
-                'gnupghome/TESTING.subkeys.sec')
-
-        self.addCleanup(self.removeRundir)
-
-    def test_getGPGContext_good_keyfile(self):
-        """Test EmailServer.getGPGContext() with a good key filename."""
-        self.setKey(self.gpgMoved)
-        ctx = crypto.getGPGContext(self.config)
-        self.assertIsInstance(ctx, crypto.gpgme.Context)
-
-    def test_getGPGContext_missing_keyfile(self):
-        """Test EmailServer.getGPGContext() with a missing key filename."""
-        self.setKey('missing-keyfile.asc')
-        ctx = crypto.getGPGContext(self.config)
-        self.assertTrue(ctx is None)
-
-    def test_getGPGContext_bad_keyfile(self):
-        """Test EmailServer.getGPGContext() with a missing key filename."""
-        self.makeBadKey()
-        ctx = crypto.getGPGContext(self.config)
-        self.assertTrue(ctx is None)





More information about the tor-commits mailing list