summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNavaL <ayoyo@thoughtworks.com>2016-11-29 19:28:52 +0100
committerRuben Pollan <meskio@sindominio.net>2017-12-03 20:43:32 +0100
commit9430464704fc58460613c4225f5a0eb59617d4b5 (patch)
treeec83219dcabd45d7dbbfe99f3500c1642ea601e9
parent6b5c2e802eef35f1752713d353d3001f43980841 (diff)
[feat] expired public key are remotely fetched if expired
- private key is not allowed to be fetched remotely - fetch_remote needs to be specifically set - if a new key is fetched (ie different KeyID), the validation rule applies
-rw-r--r--bench/keymanager/common.py47
-rw-r--r--src/leap/bitmask/keymanager/__init__.py21
-rw-r--r--tests/integration/keymanager/common.py47
-rw-r--r--tests/integration/keymanager/test_keymanager.py43
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
+
+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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/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)