diff options
| -rw-r--r-- | bench/keymanager/common.py | 47 | ||||
| -rw-r--r-- | src/leap/bitmask/keymanager/__init__.py | 21 | ||||
| -rw-r--r-- | tests/integration/keymanager/common.py | 47 | ||||
| -rw-r--r-- | tests/integration/keymanager/test_keymanager.py | 43 | 
4 files changed, 146 insertions, 12 deletions
| diff --git a/bench/keymanager/common.py b/bench/keymanager/common.py index aa907dab..3e07d0d5 100644 --- a/bench/keymanager/common.py +++ b/bench/keymanager/common.py @@ -270,6 +270,53 @@ p/c59ceStlbqgYybVHhnFtse0d/dpl7rTi0JO9sph/Mg  -----END PGP PRIVATE KEY BLOCK-----  """ +# the corresponding public key +# this is signed by the other key 2F455E2824D18DDF above + +DIFFERENT_PUBLIC_KEY = """ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +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 +=X/jT +-----END PGP PUBLIC KEY BLOCK----- +""" +  # key 7FEE575A: public key "anotheruser <anotheruser@leap.se>"  KEY_FINGERPRINT_2 = "F6E2B572ADB84EA58BD2E9A57F9DFA687FEE575A"  PUBLIC_KEY_2 = """ diff --git a/src/leap/bitmask/keymanager/__init__.py b/src/leap/bitmask/keymanager/__init__.py index e3d7fdd0..7164cb91 100644 --- a/src/leap/bitmask/keymanager/__init__.py +++ b/src/leap/bitmask/keymanager/__init__.py @@ -229,8 +229,9 @@ class KeyManager(object):          """          Return a key bound to address. -        First, search for the key in local storage. If it is not available, -        then try to fetch from nickserver. +        First, search for the key in local storage. When it is available +        locally but is expired or when it is not available locally, +        then a fetch from nickserver is tried.          :param address: The address bound to the key.          :type address: str @@ -244,6 +245,8 @@ class KeyManager(object):                   or which fails with KeyNotFound if no key was found neither                   locally or in keyserver or fail with KeyVersionError if the                   key has a format not supported by this version of KeyManager +                 or KeyNotValidUpgrade if the key is renewed remotely but fails +                 the validation rule          :rtype: Deferred          :raise UnsupportedKeyTypeError: if invalid key type @@ -255,17 +258,27 @@ class KeyManager(object):              emit_async(catalog.KEYMANAGER_KEY_FOUND, address)              return key +        def ensure_valid(key): +            if key.is_expired(): +                logger.info('Found expired key for %s.' % self._address) +                return _fetch_remotely(key) +            key_found(key) +            return key +          def key_not_found(failure):              if not failure.check(keymanager_errors.KeyNotFound):                  return failure              emit_async(catalog.KEYMANAGER_KEY_NOT_FOUND, address) +            return _fetch_remotely(failure) +        def _fetch_remotely(passthru):              # we will only try to fetch a key from nickserver if fetch_remote              # is True and the key is not private.              if fetch_remote is False or private is True: -                return failure +                return passthru +            logger.debug('Fetching remotely key for %s.' % self._address)              emit_async(catalog.KEYMANAGER_LOOKING_FOR_KEY, address)              d = self._fetch_keys_from_server_and_store_local(address)              d.addCallback( @@ -275,7 +288,7 @@ class KeyManager(object):          # return key if it exists in local database          d = self._openpgp.get_key(address, private=private) -        d.addCallbacks(key_found, key_not_found) +        d.addCallbacks(ensure_valid, key_not_found)          return d      @defer.inlineCallbacks diff --git a/tests/integration/keymanager/common.py b/tests/integration/keymanager/common.py index c2fd77be..67a14934 100644 --- a/tests/integration/keymanager/common.py +++ b/tests/integration/keymanager/common.py @@ -259,6 +259,53 @@ p/c59ceStlbqgYybVHhnFtse0d/dpl7rTi0JO9sph/Mg  -----END PGP PRIVATE KEY BLOCK-----  """ +# the corresponding public key +# this is signed by the other key 2F455E2824D18DDF above + +DIFFERENT_PUBLIC_KEY = """ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQENBFg3mmIBCAD1W0VwNfGm7hMDzqd/AX8xJcLw3WyAABpOOusEzcZLmMu8Lc6U +37LK7aJi0UQ/gHjS3Wakxt98dzDGcjIcrNh0u3Ldo776cfXGkyAcqj+dZP7xdPLc +x+WIIhZahzIL59isncT0Ou0yXpl7GpBnByXEr5oO21cKZdkD5QN5WmHcUlkNRcTx +CG7jLHhGcY00GdDXhrC7/+OaNdgceHcn2698YIzPXSVrP7oCjb25fYMZ4zZQpgsL +1Wbdr+enSzIRYAJu7pwNjwvnILergqs21SlVOJugd4PKvFZ5+IM0pJqhDwnErrQt +7syAr4B6bF99Hxze9QXiP7PbPhmYqNLNUwfFABEBAAG0HExlYXAgVGVzdCBLZXkg +PGxlYXBAbGVhcC5zZT6JATgEEwECACIFAlg3mmICGwMGCwkIBwMCBhUIAgkKCwQW +AgMBAh4BAheAAAoJEKQzeVbSfcicOoYIAN/AmWlP5HsilZzV9V0lDmAXVrWUJbIR +NYj/hit/1gf/xrc5ZmhEMi1LMeudPQJ2jVuaaU0aHVxvmDHXaHetWXVtBqAT6pCM +s69fV8HxelrZtQRZ0lTuEQ30dEur1ja5ekFqAcYIAmnA0L1qjmKS5245ctEKZL5L +OuhaBwa3LG3ehOX9+I9qXRoRsljd/GmFeHXPqawhxY5BFy3gmMU0V337mv8poTO3 +CgFjHVr8nPTx2EbPLZA6hWRf81n+MIW0ta+0llp12gtL1BGMiPf+zUE1Tv5yZBxF +YIh2rQ1Q4lwJMQnMCEDggzOK6uN2dFzVlewTCf1W0OQtPJ6/fcaIwMWJAhwEEAEC +AAYFAlg83mYACgkQL0VeKCTRjd+ZVQ//QhiH7E0DBWEYZyiPJ+ddvJ1MwDIVPEa0 +RT8P8OFH+2wipVBlJvNKTsTp0rLRblhpyibaiQJOe27swSRRLaT1UdvUrhfZaJlb +AdlNGMNoTp4INpvpLc5Jhoz88LqBhhx6FHDjmDU0KxvOPNOnHLoc9uxcvNqqSjeO +7yLJW/FLJELrqhCcu2j1pCMnvngoxe0kPtQRHYWQOaatGgjtAgLVLI79A3iqO7pB +4qh51uHmepmOp+Q5GM84malnylTHw6UnZQkWBes9fSmMQr3pdntgwopUE0WFj4la +moCKykFMdaifM1OX+EJEugd5lQF19K3zhyhLp66gp6MVjwhrDpB2EWqhKkfDyY4C +GibHWq7tBiKY8RiArJinfEdzdGLvuqOEb2+nRTYVLCPlMAuy1EH6rO6kudlgFRHl +HC44mdiC1Thvd4YhXdsBVch6CSq1JJvVoWwmVFBBO/2z20CtmKfmjj4y91y4Rb66 +NQ3yPwamqO8wnxI22J6XNhRQ5xQDtP7tSZYwC6jQ6Tee5/VPMDtpkfmPiJSCwc1i +wZZ0FJblvmzj/Zv8crvBSutDjtjJgrR5wHRRGlMexvF3YrCEQM7D93eSeMN7Cy4o +vzmcWXBbqwBHsL8BUENQI181Gz02Y+MoPRFgzQdJHIy5OfvYc2cheqjrk9tkR72Y +LvPmw3K0KW65AQ0EWDeaYgEIAM4CjkzrfVHGF0ueXssmDajDq4t29R8vXu3Xm+SG +ickUqDAWKKtK6OJKo0tPTj+FnF0secDvp3Dh+eYv76HUEth5TegTrFzbgdTAT0f4 +MJoUFVAj6mncP93hQp4sn1KAd+bP3I4krjfpDr7SRACNSaL63nMi4SaHkLxQBS+r +OmD5vk2gzzxRXcH2k363Br05q1IoWrx2V8/u2PAF1OAK8nn7IFMwm32y8ic388b+ +w+7ZDy/nTxcL8rQiTIG03z/R9WuOfPl5CW5yfKBwvwB7tbxsEa1FLZMHXAWyc/YD +U9E6MFUqlV8s6KqTJOLPhTdTS5ZnIaXvAiT1kJVygx0aTt8AEQEAAYkBHwQYAQIA +CQUCWDeaYgIbDAAKCRCkM3lW0n3InNkRCACE5++Zjc2GQSrOPZ4q8sI24FDRQr24 +zwQr3VX0GiQ6wi2rJkTRG+Wmxl27OG5A72pYBUpGgcudPi5sAzR62P2SP4K/ZK4a +S0tk3uTN4xiYLGkK8esj6Yi/ZpB1YN8LVJFobOjE2fIs6JOM6ntmP/8Y/9ocD6fY +JyrT016U1bwWrLSfncpUZYCgkVsCHl9IYZ3ZNqp1xjdvDWOQCdpFbxaN9dFoqfpO +uwupoV1/WkWKe3xEcIGgfXWW+h4aZLlmMEJJebt+UOiSsawPTsLQNJAs4JWAyE3w +3GKS7JYVRnSKp/c59ceStlbqgYybVHhnFtse0d/dpl7rTi0JO9sph/Mg +=X/jT +-----END PGP PUBLIC KEY BLOCK----- +""" +  # key 7FEE575A: public key "anotheruser <anotheruser@leap.se>"  KEY_FINGERPRINT_2 = "F6E2B572ADB84EA58BD2E9A57F9DFA687FEE575A"  PUBLIC_KEY_2 = """ diff --git a/tests/integration/keymanager/test_keymanager.py b/tests/integration/keymanager/test_keymanager.py index ed734332..6a6feb31 100644 --- a/tests/integration/keymanager/test_keymanager.py +++ b/tests/integration/keymanager/test_keymanager.py @@ -49,11 +49,13 @@ from common import (      PRIVATE_KEY,      PRIVATE_KEY_2,      ADDRESS_EXPIRING, -    KEY_EXPIRING_CREATION_DATE,      PRIVATE_EXPIRING_KEY,      NEW_PUB_KEY,      OLD_AND_NEW_KEY_ADDRESS, -    DIFFERENT_PRIVATE_KEY, DIFFERENT_KEY_FPR) +    DIFFERENT_PRIVATE_KEY, +    DIFFERENT_KEY_FPR, +    DIFFERENT_PUBLIC_KEY, +)  NICKSERVER_URI = "http://leap.se/"  REMOTE_KEY_URL = "http://site.domain/key" @@ -171,6 +173,28 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase):          self.assertFalse(key.private)      @defer.inlineCallbacks +    def test_get_public_key_fetches_remotely_if_key_expired(self): +        km = self._key_manager() +        nicknym_response = {'address': ADDRESS, +                            'openpgp': DIFFERENT_PUBLIC_KEY} +        km._nicknym.fetch_key_with_address = mock.Mock( +            return_value=nicknym_response) +        # put key +        yield km._openpgp.put_raw_key(PUBLIC_KEY, ADDRESS) + +        # get the key +        with mock.patch('leap.bitmask.keymanager.keys.OpenPGPKey.is_expired', +                        return_value=True): +            key = yield km.get_key(ADDRESS, private=False, +                                   fetch_remote=True) + +        km._nicknym.fetch_key_with_address.assert_called_once_with(ADDRESS) +        self.assertTrue(key is not None) +        self.assertEqual( +            key.fingerprint.lower(), DIFFERENT_KEY_FPR.lower()) +        self.assertFalse(key.private) + +    @defer.inlineCallbacks      def test_get_public_key_with_binary_private_key(self):          km = self._key_manager()          yield km._openpgp.put_raw_key(self.get_private_binary_key(), ADDRESS) @@ -577,13 +601,14 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase):          km = self._key_manager(user=ADDRESS_EXPIRING)          yield km._openpgp.put_raw_key(PRIVATE_EXPIRING_KEY, ADDRESS_EXPIRING) -        old_key = yield km.get_key(ADDRESS_EXPIRING) +        old_key = yield km.get_key(ADDRESS_EXPIRING, fetch_remote=False)          new_key = yield km.regenerate_key()          today = datetime.now()          new_expiry_date = date(today.year + 1, today.month, today.day) -        renewed_public_key = yield km.get_key(ADDRESS_EXPIRING) +        renewed_public_key = yield km.get_key(ADDRESS_EXPIRING, +                                              fetch_remote=False)          renewed_private_key = yield km.get_key(ADDRESS_EXPIRING, private=True)          self.assertEqual(new_expiry_date, @@ -600,11 +625,12 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase):          km = self._key_manager(user=ADDRESS_EXPIRING)          yield km._openpgp.put_raw_key(PRIVATE_EXPIRING_KEY, ADDRESS_EXPIRING) -        old_key = yield km.get_key(ADDRESS_EXPIRING) +        old_key = yield km.get_key(ADDRESS_EXPIRING, fetch_remote=False)          new_key = yield km.regenerate_key()          inactive_private_keys = yield km.get_inactive_private_keys() -        renewed_public_key = yield km.get_key(ADDRESS_EXPIRING, private=False) +        renewed_public_key = yield km.get_key(ADDRESS_EXPIRING, private=False, +                                              fetch_remote=False)          self.assertEqual(1, len(inactive_private_keys))          retrieved_old_key = inactive_private_keys[0] @@ -632,14 +658,15 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase):          km = self._key_manager(user=ADDRESS_EXPIRING)          yield km._openpgp.put_raw_key(PRIVATE_EXPIRING_KEY, ADDRESS_EXPIRING) -        key = yield km.get_key(ADDRESS_EXPIRING) +        key = yield km.get_key(ADDRESS_EXPIRING, fetch_remote=False)          invalid_validity_option = '2xw'          with self.assertRaises(KeyExpiryExtensionError):              yield km.extend_key(validity=invalid_validity_option) -        renewed_public_key = yield km.get_key(ADDRESS_EXPIRING) +        renewed_public_key = yield km.get_key(ADDRESS_EXPIRING, +                                              fetch_remote=False)          renewed_private_key = yield km.get_key(ADDRESS_EXPIRING, private=True)          self.assertEqual(key.expiry_date, renewed_public_key.expiry_date) | 
