diff options
| -rw-r--r-- | keymanager/changes/feature-expose-methods | 2 | ||||
| -rw-r--r-- | keymanager/src/leap/keymanager/__init__.py | 42 | ||||
| -rw-r--r-- | keymanager/src/leap/keymanager/errors.py | 12 | ||||
| -rw-r--r-- | keymanager/src/leap/keymanager/openpgp.py | 69 | 
4 files changed, 107 insertions, 18 deletions
| diff --git a/keymanager/changes/feature-expose-methods b/keymanager/changes/feature-expose-methods new file mode 100644 index 0000000..92b30d5 --- /dev/null +++ b/keymanager/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). diff --git a/keymanager/src/leap/keymanager/__init__.py b/keymanager/src/leap/keymanager/__init__.py index 61213d3..dbc5489 100644 --- a/keymanager/src/leap/keymanager/__init__.py +++ b/keymanager/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/keymanager/src/leap/keymanager/errors.py b/keymanager/src/leap/keymanager/errors.py index 89949d2..27180db 100644 --- a/keymanager/src/leap/keymanager/errors.py +++ b/keymanager/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/keymanager/src/leap/keymanager/openpgp.py b/keymanager/src/leap/keymanager/openpgp.py index 1670e1c..f6223d5 100644 --- a/keymanager/src/leap/keymanager/openpgp.py +++ b/keymanager/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):          """ @@ -395,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) | 
