From 4162fd5a7e6485fdcf068af06a743c1ef7676a50 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Sun, 14 Dec 2014 22:13:57 -0600 Subject: Return the right error on signature verification --- src/leap/keymanager/__init__.py | 79 ++++++++++++++-------------- src/leap/keymanager/errors.py | 7 +++ src/leap/keymanager/tests/test_keymanager.py | 3 +- 3 files changed, 48 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index 7ff437e..5324d42 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -54,7 +54,8 @@ from leap.keymanager.errors import ( KeyNotFound, KeyAddressMismatch, KeyNotValidUpgrade, - UnsupportedKeyTypeError + UnsupportedKeyTypeError, + InvalidSignature ) from leap.keymanager.validation import ValidationLevel, can_upgrade @@ -479,7 +480,12 @@ class KeyManager(object): data, pubkey, passphrase, sign=signkey, cipher_algo=cipher_algo) - d = self._get_keys(ktype, address, sign, fetch_remote=fetch_remote) + dpub = self.get_key(address, ktype, private=False, + fetch_remote=fetch_remote) + dpriv = defer.succeed(None) + if sign is not None: + dpriv = self.get_key(sign, ktype, private=True) + d = defer.gatherResults([dpub, dpriv]) d.addCallback(encrypt) return d @@ -504,11 +510,12 @@ class KeyManager(object): to fetch from nickserver :type fetch_remote: bool - :return: A Deferred which fires with the decrypted data as str and the - signing EncryptionKey if signature verifies, or which fails - with KeyNotFound if no keys were found neither locally or in - keyserver or fails with DecryptError if failed decrypting for - some reason. + :return: A Deferred which fires with: + * (decripted str, signing key) if validation works + * (decripted str, KeyNotFound) if signing key not found + * (decripted str, InvalidSignature) if signature is invalid + * KeyNotFound failure if private key not found + * DecryptError failure if decription failed :rtype: Deferred :raise UnsupportedKeyTypeError: if invalid key type @@ -519,39 +526,25 @@ class KeyManager(object): pubkey, privkey = keys decrypted, signed = self._wrapper_map[ktype].decrypt( data, privkey, passphrase=passphrase, verify=pubkey) - return (decrypted, pubkey if signed else None) - - d = self._get_keys(ktype, verify, address, fetch_remote) - d.addCallback(decrypt) - return d - - def _get_keys(self, ktype, public, private, fetch_remote=True): - """ - Get public and private keys of ktype. - - :param ktype: The type of the key. - :type ktype: subclass of EncryptionKey - :param public: The address of the public key. - :type public: str - :param private: The address of the private key. - :type private: str - :param fetch_remote: If key for verify not found in local storage try - to fetch from nickserver - :type fetch_remote: bool + if pubkey is None: + signature = KeyNotFound(verify) + elif signed: + signature = pubkey + else: + signature = InvalidSignature( + 'Failed to verify signature with key %s' % + (pubkey.key_id,)) + return (decrypted, signature) - :return: A Deferred which fires with a tuple with public and private - EncryptionKeys, or which fails with KeyNotFound if no keys - were found neither locally or in keyserver. - :rtype: Deferred - """ + dpriv = self.get_key(address, ktype, private=True) dpub = defer.succeed(None) - if public is not None: - dpub = self.get_key(public, ktype, private=False, + if verify is not None: + dpub = self.get_key(verify, ktype, private=False, fetch_remote=fetch_remote) - dpriv = defer.succeed(None) - if private is not None: - dpriv = self.get_key(private, ktype, private=True) - return defer.gatherResults([dpub, dpriv]) + dpub.addErrback(lambda f: None if f.check(KeyNotFound) else f) + d = defer.gatherResults([dpub, dpriv]) + d.addCallback(decrypt) + return d def sign(self, data, address, ktype, digest_algo='SHA512', clearsign=False, detach=True, binary=False): @@ -612,8 +605,9 @@ class KeyManager(object): :type fetch_remote: bool :return: A Deferred which fires with the signing EncryptionKey if - signature verifies else None, or which fails with KeyNotFound - if no key was found neither locally or in keyserver. + signature verifies, or which fails with InvalidSignature if + signature don't verifies or fails with KeyNotFound if no key + was found neither locally or in keyserver. :rtype: Deferred :raise UnsupportedKeyTypeError: if invalid key type @@ -623,7 +617,12 @@ class KeyManager(object): def verify(pubkey): signed = self._wrapper_map[ktype].verify( data, pubkey, detached_sig=detached_sig) - return pubkey if signed else None + if signed: + return pubkey + else: + raise InvalidSignature( + 'Failed to verify signature with key %s' % + (pubkey.key_id,)) d = self.get_key(address, ktype, private=False, fetch_remote=fetch_remote) diff --git a/src/leap/keymanager/errors.py b/src/leap/keymanager/errors.py index 4041837..8a9fb3c 100644 --- a/src/leap/keymanager/errors.py +++ b/src/leap/keymanager/errors.py @@ -51,6 +51,13 @@ class NoPasswordGiven(Exception): pass +class InvalidSignature(Exception): + """ + Raised when signature could not be verified. + """ + pass + + class EncryptError(Exception): """ Raised upon failures of encryption. diff --git a/src/leap/keymanager/tests/test_keymanager.py b/src/leap/keymanager/tests/test_keymanager.py index b8ef88a..dca89e8 100644 --- a/src/leap/keymanager/tests/test_keymanager.py +++ b/src/leap/keymanager/tests/test_keymanager.py @@ -29,6 +29,7 @@ from twisted.trial import unittest from leap.keymanager import ( KeyNotFound, KeyAddressMismatch, + errors ) from leap.keymanager.openpgp import OpenPGPKey from leap.keymanager.keys import ( @@ -357,7 +358,7 @@ class KeyManagerCryptoTestCase(KeyManagerWithSoledadTestCase): rawdata, signingkey = yield km.decrypt( encdata, ADDRESS, OpenPGPKey, verify=ADDRESS, fetch_remote=False) self.assertEqual(self.RAW_DATA, rawdata) - self.assertTrue(signingkey is None) + self.assertTrue(isinstance(signingkey, errors.InvalidSignature)) @inlineCallbacks def test_keymanager_openpgp_sign_verify(self): -- cgit v1.2.3