From 0050dcd11137f544c6c78d236163e19f76a24b38 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 13 Nov 2013 18:09:15 -0300 Subject: Refactor code to support parsing ascii keys. --- src/leap/keymanager/errors.py | 12 ++++++++ src/leap/keymanager/openpgp.py | 63 ++++++++++++++++++++++++++++++------------ 2 files changed, 58 insertions(+), 17 deletions(-) diff --git a/src/leap/keymanager/errors.py b/src/leap/keymanager/errors.py index 89949d2..27180db 100644 --- a/src/leap/keymanager/errors.py +++ b/src/leap/keymanager/errors.py @@ -84,3 +84,15 @@ class SignFailed(Exception): Raised when failed to sign. """ pass + + +class KeyAddressMismatch(Exception): + """ + A mismatch between addresses. + """ + + +class KeyFingerprintMismatch(Exception): + """ + A mismatch between fingerprints. + """ diff --git a/src/leap/keymanager/openpgp.py b/src/leap/keymanager/openpgp.py index 1670e1c..78acd6a 100644 --- a/src/leap/keymanager/openpgp.py +++ b/src/leap/keymanager/openpgp.py @@ -35,7 +35,7 @@ from gnupg import GPG from gnupg.gnupg import GPGUtilities from gnupg._util import _make_binary_stream -from leap.common.check import leap_assert, leap_assert_type +from leap.common.check import leap_assert, leap_assert_type, leap_check from leap.keymanager import errors from leap.keymanager.keys import ( EncryptionKey, @@ -303,16 +303,22 @@ class OpenPGPScheme(EncryptionScheme): raise errors.KeyNotFound(address) return build_key_from_dict(OpenPGPKey, address, doc.content) - def put_ascii_key(self, key_data): + def parse_ascii_key(self, key_data): """ - Put key contained in ascii-armored C{key_data} in local storage. + Parses an ascii armored key (or key pair) data and returns + the OpenPGPKey keys. - :param key_data: The key data to be stored. + :param key_data: the key data to be parsed. :type key_data: str or unicode + + :returns: the public key and private key (if applies) for that data. + :rtype: (public, private) -> tuple(OpenPGPKey, OpenPGPKey) + the tuple may have one or both components None """ leap_assert_type(key_data, (str, unicode)) # TODO: add more checks for correct key data. leap_assert(key_data is not None, 'Data does not represent a key.') + mail_regex = '.*<([\w.-]+@[\w.-]+)>.*' with self._temporary_gpgwrapper() as gpg: # TODO: inspect result, or use decorator @@ -325,31 +331,54 @@ class OpenPGPScheme(EncryptionScheme): except IndexError: pass pubkey = gpg.list_keys(secret=False).pop() # unitary keyring + # extract adress from first uid on key - match = re.match('.*<([\w.-]+@[\w.-]+)>.*', pubkey['uids'].pop()) + match = re.match(mail_regex, pubkey['uids'].pop()) leap_assert(match is not None, 'No user address in key data.') address = match.group(1) + if privkey is not None: - match = re.match( - '.*<([\w.-]+@[\w.-]+)>.*', privkey['uids'].pop()) + match = re.match(mail_regex, privkey['uids'].pop()) leap_assert(match is not None, 'No user address in key data.') privaddress = match.group(1) - leap_assert( - address == privaddress, - 'Addresses in pub and priv key differ.') - leap_assert( - pubkey['fingerprint'] == privkey['fingerprint'], - 'Fingerprints for pub and priv key differ.') - # insert private key in storage + + # build private key openpgp_privkey = _build_key_from_gpg( - address, privkey, + privaddress, privkey, gpg.export_keys(privkey['fingerprint'], secret=True)) - self.put_key(openpgp_privkey) - # insert public key in storage + + leap_check(address == privaddress, + 'Addresses in public and private key differ.', + errors.KeyAddressMismatch) + leap_check(pubkey['fingerprint'] == privkey['fingerprint'], + 'Fingerprints for public and private key differ.', + errors.KeyFingerprintMismatch) + + # build public key openpgp_pubkey = _build_key_from_gpg( address, pubkey, gpg.export_keys(pubkey['fingerprint'], secret=False)) + + return (openpgp_pubkey, openpgp_privkey) + + def put_ascii_key(self, key_data): + """ + Put key contained in ascii-armored C{key_data} in local storage. + + :param key_data: The key data to be stored. + :type key_data: str or unicode + """ + leap_assert_type(key_data, (str, unicode)) + + try: + openpgp_pubkey, openpgp_privkey = self.parse_ascii_key(key_data) + except (errors.KeyAddressMismatch, errors.KeyFingerprintMismatch) as e: + leap_assert(False, repr(e)) + + if openpgp_pubkey is not None: self.put_key(openpgp_pubkey) + if openpgp_privkey is not None: + self.put_key(openpgp_privkey) def put_key(self, key): """ -- cgit v1.2.3 From 875f8ed071f3dae06818eba992a8dd8ddc2298b3 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 14 Nov 2013 11:59:28 -0300 Subject: Expose openpgp methods in keymanager. - parse_ascii_key - delete_key - put_key --- src/leap/keymanager/__init__.py | 42 +++++++++++++++++++++++++++++++++++++++++ src/leap/keymanager/openpgp.py | 6 +++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index 61213d3..dbc5489 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -495,6 +495,48 @@ class KeyManager(object): return self._wrapper_map[pubkey.__class__].verify( data, pubkey, detached_sig=detached_sig) + def parse_openpgp_ascii_key(self, key_data): + """ + Parses an ascii armored key (or key pair) data and returns + the OpenPGPKey keys. + + :param key_data: the key data to be parsed. + :type key_data: str or unicode + + :returns: the public key and private key (if applies) for that data. + :rtype: (public, private) -> tuple(OpenPGPKey, OpenPGPKey) + the tuple may have one or both components None + """ + return self._wrapper_map[OpenPGPKey].parse_ascii_key(key_data) + + def delete_key(self, key): + """ + Remove C{key} from storage. + + May raise: + openpgp.errors.KeyNotFound + openpgp.errors.KeyAttributesDiffer + + :param key: The key to be removed. + :type key: EncryptionKey + """ + try: + self._wrapper_map[type(key)].delete_key(key) + except IndexError as e: + leap_assert(False, "Unsupported key type. Error {0!r}".format(e)) + + def put_key(self, key): + """ + Put C{key} in local storage. + + :param key: The key to be stored. + :type key: OpenPGPKey + """ + try: + self._wrapper_map[type(key)].put_key(key) + except IndexError as e: + leap_assert(False, "Unsupported key type. Error {0!r}".format(e)) + from ._version import get_versions __version__ = get_versions()['version'] del get_versions diff --git a/src/leap/keymanager/openpgp.py b/src/leap/keymanager/openpgp.py index 78acd6a..f6223d5 100644 --- a/src/leap/keymanager/openpgp.py +++ b/src/leap/keymanager/openpgp.py @@ -424,10 +424,14 @@ class OpenPGPScheme(EncryptionScheme): """ Remove C{key} from storage. + May raise: + errors.KeyNotFound + errors.KeyAttributesDiffer + :param key: The key to be removed. :type key: EncryptionKey """ - leap_assert(key.__class__ is OpenPGPKey, 'Wrong key type.') + leap_assert_type(key, OpenPGPKey) stored_key = self.get_key(key.address, private=key.private) if stored_key is None: raise errors.KeyNotFound(key) -- cgit v1.2.3 From d88afefd26592f91edbf3f5a2eea165508ca4afa Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 14 Nov 2013 12:07:30 -0300 Subject: Add changes file. --- changes/feature-expose-methods | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 changes/feature-expose-methods diff --git a/changes/feature-expose-methods b/changes/feature-expose-methods new file mode 100644 index 0000000..92b30d5 --- /dev/null +++ b/changes/feature-expose-methods @@ -0,0 +1,2 @@ + o New openpgp method: parse_ascii_keys. + o Expose openpgp methods in keymanager (parse_ascii_keys, put_key, delete_key). -- cgit v1.2.3