From 3ebb6be0c628b3a2b45a28690b6b6dc1bb2ae850 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Sun, 12 Oct 2014 03:21:47 -0500 Subject: Basic validation levels support --- src/leap/keymanager/__init__.py | 96 +++++++++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 22 deletions(-) (limited to 'src/leap/keymanager/__init__.py') diff --git a/src/leap/keymanager/__init__.py b/src/leap/keymanager/__init__.py index c3423d9..156aaf8 100644 --- a/src/leap/keymanager/__init__.py +++ b/src/leap/keymanager/__init__.py @@ -48,7 +48,12 @@ from leap.common.events import signal from leap.common.events import events_pb2 as proto from leap.common.decorators import memoized_method -from leap.keymanager.errors import KeyNotFound, KeyAttributesDiffer +from leap.keymanager.errors import ( + KeyNotFound, + KeyAddressMismatch, + KeyNotValidUpgrade +) +from leap.keymanager.validation import ValidationLevel, can_upgrade from leap.keymanager.keys import ( EncryptionKey, @@ -208,8 +213,11 @@ class KeyManager(object): server_keys = res.json() # insert keys in local database if self.OPENPGP_KEY in server_keys: - self._wrapper_map[OpenPGPKey].put_ascii_key( - server_keys['openpgp']) + self.put_raw_key( + server_keys['openpgp'], + OpenPGPKey, + address=address, + validation=ValidationLevel.Provider_Trust) except requests.exceptions.HTTPError as e: if e.response.status_code == 404: raise KeyNotFound(address) @@ -230,7 +238,7 @@ class KeyManager(object): replace any prior keys for the same address in its database. :param ktype: The type of the key. - :type ktype: KeyType + :type ktype: subclass of EncryptionKey :raise KeyNotFound: If the key was not found in local database. """ @@ -260,7 +268,7 @@ class KeyManager(object): :param address: The address bound to the key. :type address: str :param ktype: The type of the key. - :type ktype: KeyType + :type ktype: subclass of EncryptionKey :param private: Look for a private key instead of a public one? :type private: bool :param fetch_remote: If key not found in local storage try to fetch @@ -323,7 +331,7 @@ class KeyManager(object): Generate a key of type C{ktype} bound to the user's address. :param ktype: The type of the key. - :type ktype: KeyType + :type ktype: subclass of EncryptionKey :return: The generated key. :rtype: EncryptionKey @@ -515,32 +523,74 @@ class KeyManager(object): """ Put C{key} in local storage. - :param key: The key to be stored. It can be ascii key or an OpenPGPKey - :type key: str or OpenPGPKey + :param key: The key to be stored + :type key: EncryptionKey + :raises KeyNotValidUpdate: if a key with the same uid exists and the + new one is not a valid update for it """ try: - if isinstance(key, basestring): - self._wrapper_map[OpenPGPKey].put_ascii_key(key) - else: + old_key = self._wrapper_map[type(key)].get_key(key.address, + private=key.private) + except KeyNotFound: + old_key = None + + if key.private or can_upgrade(key, old_key): + try: self._wrapper_map[type(key)].put_key(key) - except IndexError as e: - leap_assert(False, "Unsupported key type. Error {0!r}".format(e)) + except IndexError as e: + leap_assert( + False, "Unsupported key type. Error {0!r}".format(e)) + else: + raise KeyNotValidUpgrade("Key %s can not be upgraded by new key %s" + % (old_key.key_id, key.key_id)) - def fetch_key(self, address, uri, ktype): + def put_raw_key(self, key, ktype, address=None, + validation=ValidationLevel.Weak_Chain): + """ + Put C{key} in local storage. + + :param key: The ascii key to be stored + :type key: str + :param ktype: the type of the key. + :type ktype: subclass of EncryptionKey + :param address: if set used to check that the key is for this address + :type address: str + :param validation: validation level for this key + (default: 'Weak_Chain') + :type validation: ValidationLevel + + :raises KeyAddressMismatch: if address doesn't match any uid on the key + :raises KeyNotValidUpdate: if a key with the same uid exists and the + new one is not a valid update for it + """ + pubkey, _ = self._wrapper_map[ktype].parse_ascii_key(key) + if address is not None and address != pubkey.address: + raise KeyAddressMismatch("Key UID %s, but expected %s" + % (pubkey.address, address)) + + pubkey.validation = validation + self.put_key(pubkey) + + def fetch_key(self, address, uri, ktype, + validation=ValidationLevel.Weak_Chain): """ Fetch a public key for C{address} from the network and put it in local storage. - Raises C{openpgp.errors.KeyNotFound} if not valid key on C{uri}. - Raises C{openpgp.errors.KeyAttributesDiffer} if address don't match - any uid on the key. - :param address: The email address of the key. :type address: str :param uri: The URI of the key. :type uri: str - :param ktype: The type of the key. - :type ktype: KeyType + :param ktype: the type of the key. + :type ktype: subclass of EncryptionKey + :param validation: validation level for this key + (default: 'Weak_Chain') + :type validation: ValidationLevel + + :raises KeyNotFound: if not valid key on C{uri} + :raises KeyAddressMismatch: if address doesn't match any uid on the key + :raises KeyNotValidUpdate: if a key with the same uid exists and the + new one is not a valid update for it """ res = self._get(uri) if not res.ok: @@ -551,8 +601,10 @@ class KeyManager(object): if pubkey is None: raise KeyNotFound(uri) if pubkey.address != address: - raise KeyAttributesDiffer("UID %s found, but expected %s" - % (pubkey.address, address)) + raise KeyAddressMismatch("UID %s found, but expected %s" + % (pubkey.address, address)) + + pubkey.validation = validation self.put_key(pubkey) from ._version import get_versions -- cgit v1.2.3