diff options
Diffstat (limited to 'keymanager')
-rw-r--r-- | keymanager/CHANGELOG | 7 | ||||
-rw-r--r-- | keymanager/changes/VERSION_COMPAT | 0 | ||||
-rw-r--r-- | keymanager/src/leap/keymanager/__init__.py | 3 | ||||
-rw-r--r-- | keymanager/src/leap/keymanager/errors.py | 6 | ||||
-rw-r--r-- | keymanager/src/leap/keymanager/openpgp.py | 83 |
5 files changed, 67 insertions, 32 deletions
diff --git a/keymanager/CHANGELOG b/keymanager/CHANGELOG index e20b86c8..a081cc50 100644 --- a/keymanager/CHANGELOG +++ b/keymanager/CHANGELOG @@ -1,3 +1,10 @@ +0.3.7 Dec 6: + o Fix error return values on openpgp backend. + o Remove address check when sending email and rely in the email + client to verify that is correct. Closes #4491. + o Support sending encrypted mails to addresses using the '+' sign. + o Improve exception names and handling. + 0.3.6 Nov 15: o Default encoding to 'utf-8' in case of system encodings not set. Closes #4427. diff --git a/keymanager/changes/VERSION_COMPAT b/keymanager/changes/VERSION_COMPAT new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/keymanager/changes/VERSION_COMPAT diff --git a/keymanager/src/leap/keymanager/__init__.py b/keymanager/src/leap/keymanager/__init__.py index dbc54891..6cfbf710 100644 --- a/keymanager/src/leap/keymanager/__init__.py +++ b/keymanager/src/leap/keymanager/__init__.py @@ -425,6 +425,9 @@ class KeyManager(object): :type data: str :param privkey: The key used to decrypt. :type privkey: OpenPGPKey + :param passphrase: The passphrase for the secret key used for + decryption. + :type passphrase: str :param verify: The key used to verify a signature. :type verify: OpenPGPKey diff --git a/keymanager/src/leap/keymanager/errors.py b/keymanager/src/leap/keymanager/errors.py index 27180dbd..ebe4fd5e 100644 --- a/keymanager/src/leap/keymanager/errors.py +++ b/keymanager/src/leap/keymanager/errors.py @@ -58,21 +58,21 @@ class InvalidSignature(Exception): pass -class EncryptionFailed(Exception): +class EncryptError(Exception): """ Raised upon failures of encryption. """ pass -class DecryptionFailed(Exception): +class DecryptError(Exception): """ Raised upon failures of decryption. """ pass -class EncryptionDecryptionFailed(Exception): +class GPGError(Exception): """ Raised upon failures of encryption/decryption. """ diff --git a/keymanager/src/leap/keymanager/openpgp.py b/keymanager/src/leap/keymanager/openpgp.py index f6223d57..856b21e4 100644 --- a/keymanager/src/leap/keymanager/openpgp.py +++ b/keymanager/src/leap/keymanager/openpgp.py @@ -297,7 +297,11 @@ class OpenPGPScheme(EncryptionScheme): :rtype: OpenPGPKey @raise KeyNotFound: If the key was not found on local storage. """ - leap_assert(is_address(address), 'Not an user address: %s' % address) + # Remove the identity suffix after the '+' until the '@' + # e.g.: test_user+something@provider.com becomes test_user@probider.com + # since the key belongs to the identity without the '+' suffix. + address = re.sub(r'\+.*\@', '@', address) + doc = self._get_key_doc(address, private) if doc is None: raise errors.KeyNotFound(address) @@ -337,6 +341,7 @@ class OpenPGPScheme(EncryptionScheme): leap_assert(match is not None, 'No user address in key data.') address = match.group(1) + openpgp_privkey = None if privkey is not None: match = re.match(mail_regex, privkey['uids'].pop()) leap_assert(match is not None, 'No user address in key data.') @@ -370,6 +375,7 @@ class OpenPGPScheme(EncryptionScheme): """ leap_assert_type(key_data, (str, unicode)) + openpgp_privkey = None try: openpgp_pubkey, openpgp_privkey = self.parse_ascii_key(key_data) except (errors.KeyAddressMismatch, errors.KeyFingerprintMismatch) as e: @@ -465,14 +471,18 @@ class OpenPGPScheme(EncryptionScheme): def _assert_gpg_result_ok(result): """ Check if GPG result is 'ok' and log stderr outputs. - :param result: The GPG results - :type result: + + :param result: GPG results, which have a field calld 'ok' that states + whether the gpg operation was successful or not. + :type result: object + + :raise GPGError: Raised when the gpg operation was not successful. """ stderr = getattr(result, 'stderr', None) if stderr: logger.debug("%s" % (stderr,)) if getattr(result, 'ok', None) is not True: - raise errors.EncryptionDecryptionFailed( + raise errors.GPGError( 'Failed to encrypt/decrypt: %s' % stderr) def encrypt(self, data, pubkey, passphrase=None, sign=None, @@ -491,6 +501,8 @@ class OpenPGPScheme(EncryptionScheme): :return: The encrypted data. :rtype: str + + :raise EncryptError: Raised if failed encrypting for some reason. """ leap_assert_type(pubkey, OpenPGPKey) leap_assert(pubkey.private is False, 'Key is not public.') @@ -509,8 +521,12 @@ class OpenPGPScheme(EncryptionScheme): # in the ciphertext. # result.ok - (bool) indicates if the operation succeeded # result.data - (bool) contains the result of the operation - self._assert_gpg_result_ok(result) - return result.data + try: + self._assert_gpg_result_ok(result) + return result.data + except errors.GPGError as e: + logger.error('Failed to decrypt: %s.' % str(e)) + raise error.EncryptError() def decrypt(self, data, privkey, passphrase=None, verify=None): """ @@ -520,14 +536,18 @@ class OpenPGPScheme(EncryptionScheme): :type data: str :param privkey: The key used to decrypt. :type privkey: OpenPGPKey + :param passphrase: The passphrase for the secret key used for + decryption. + :type passphrase: str :param verify: The key used to verify a signature. :type verify: OpenPGPKey :return: The decrypted data. :rtype: unicode - @raise InvalidSignature: Raised if unable to verify the signature with - C{verify} key. + :raise DecryptError: Raised if failed decrypting for some reason. + :raise InvalidSignature: Raised if unable to verify the signature with + C{verify} key. """ leap_assert(privkey.private is True, 'Key is not private.') keys = [privkey] @@ -536,26 +556,31 @@ class OpenPGPScheme(EncryptionScheme): leap_assert(verify.private is False) keys.append(verify) with self._temporary_gpgwrapper(keys) as gpg: - result = gpg.decrypt( - data, passphrase=passphrase, always_trust=True) - self._assert_gpg_result_ok(result) - # verify signature - if (verify is not None): - if result.valid is False or \ - verify.fingerprint != result.pubkey_fingerprint: - raise errors.InvalidSignature( - 'Failed to verify signature with key %s: %s' % - (verify.key_id, stderr)) - - # XXX: this is the encoding used by gpg module - # https://github.com/isislovecruft/python-gnupg/\ - # blob/master/gnupg/_meta.py#L121 - encoding = locale.getpreferredencoding() - if encoding is None: - encoding = sys.stdin.encoding - if encoding is None: - encoding = 'utf-8' - return result.data.decode(encoding, 'replace') + try: + result = gpg.decrypt( + data, passphrase=passphrase, always_trust=True) + self._assert_gpg_result_ok(result) + # verify signature + if (verify is not None): + if result.valid is False or \ + verify.fingerprint != result.pubkey_fingerprint: + raise errors.InvalidSignature( + 'Failed to verify signature with key %s: %s' % + (verify.key_id, result.stderr)) + + # XXX: this is the encoding used by gpg module + # https://github.com/isislovecruft/python-gnupg/\ + # blob/master/gnupg/_meta.py#L121 + encoding = locale.getpreferredencoding() + if encoding is None: + encoding = sys.stdin.encoding + if encoding is None: + encoding = 'utf-8' + return result.data.decode(encoding, 'replace') + except errors.GPGError as e: + logger.error('Failed to decrypt: %s.' % str(e)) + raise errors.DecryptError(str(e)) + def is_encrypted(self, data): """ @@ -608,7 +633,7 @@ class OpenPGPScheme(EncryptionScheme): if result.fingerprint is None: raise errors.SignFailed( 'Failed to sign with key %s: %s' % - (privkey['keyid'], stderr)) + (privkey['keyid'], result.stderr)) leap_assert( result.fingerprint == kfprint, 'Signature and private key fingerprints mismatch: ' |