diff options
author | Tomás Touceda <chiiph@leap.se> | 2013-11-14 15:36:32 -0300 |
---|---|---|
committer | Tomás Touceda <chiiph@leap.se> | 2013-11-14 15:36:32 -0300 |
commit | e137a622440779acada41fe16a07bf4598645c06 (patch) | |
tree | ba5ac3ce859cfda7213b9c359e34bd2fc3be7da8 | |
parent | 4daab9b4bb279679611c1e4ec51c08f5987be27c (diff) | |
parent | d88afefd26592f91edbf3f5a2eea165508ca4afa (diff) |
Merge remote-tracking branch 'ivan/feature/advanced_key_management' into develop
-rw-r--r-- | changes/feature-expose-methods | 2 | ||||
-rw-r--r-- | src/leap/keymanager/__init__.py | 42 | ||||
-rw-r--r-- | src/leap/keymanager/errors.py | 12 | ||||
-rw-r--r-- | src/leap/keymanager/openpgp.py | 69 |
4 files changed, 107 insertions, 18 deletions
diff --git a/changes/feature-expose-methods b/changes/feature-expose-methods new file mode 100644 index 00000000..92b30d5c --- /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). diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index 61213d38..dbc54891 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/errors.py b/src/leap/keymanager/errors.py index 89949d29..27180dbd 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 1670e1c9..f6223d57 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): """ @@ -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) |