diff options
author | drebs <drebs@leap.se> | 2014-11-10 16:18:17 -0200 |
---|---|---|
committer | drebs <drebs@leap.se> | 2014-11-10 16:18:17 -0200 |
commit | 27776fbab6fe963082a882dfb5232c54b0195d5f (patch) | |
tree | 51780a96c6df649ce0245ce4c63a5fe9a530649b /src | |
parent | a5cf287dabc77b7172c2f058696cee1024ea3297 (diff) | |
parent | c223cca848e854d0015314ef517a6a4f928a2d0a (diff) |
Merge remote-tracking branch 'meskio/feature/6210_key_newer' into develop
Diffstat (limited to 'src')
-rw-r--r-- | src/leap/keymanager/keys.py | 24 | ||||
-rw-r--r-- | src/leap/keymanager/openpgp.py | 19 | ||||
-rw-r--r-- | src/leap/keymanager/tests/test_keymanager.py | 4 | ||||
-rw-r--r-- | src/leap/keymanager/tests/test_validation.py | 44 | ||||
-rw-r--r-- | src/leap/keymanager/validation.py | 10 |
5 files changed, 80 insertions, 21 deletions
diff --git a/src/leap/keymanager/keys.py b/src/leap/keymanager/keys.py index ecb0a36a..a61a8c79 100644 --- a/src/leap/keymanager/keys.py +++ b/src/leap/keymanager/keys.py @@ -30,6 +30,7 @@ import re from abc import ABCMeta, abstractmethod +from datetime import datetime from leap.common.check import leap_assert from leap.keymanager.validation import ValidationLevel, toValidationLevel @@ -118,6 +119,10 @@ def build_key_from_dict(kClass, address, kdict): (kdict[KEY_VALIDATION_KEY], kdict[KEY_ID_KEY])) validation = ValidationLevel.Weak_Chain + expiry_date = None + if kdict[KEY_EXPIRY_DATE_KEY]: + expiry_date = datetime.fromtimestamp(int(kdict[KEY_EXPIRY_DATE_KEY])) + return kClass( address, key_id=kdict[KEY_ID_KEY], @@ -125,7 +130,7 @@ def build_key_from_dict(kClass, address, kdict): key_data=kdict[KEY_DATA_KEY], private=kdict[KEY_PRIVATE_KEY], length=kdict[KEY_LENGTH_KEY], - expiry_date=kdict[KEY_EXPIRY_DATE_KEY], + expiry_date=expiry_date, first_seen_at=kdict[KEY_FIRST_SEEN_AT_KEY], last_audited_at=kdict[KEY_LAST_AUDITED_AT_KEY], validation=validation, @@ -141,16 +146,7 @@ class EncryptionKey(object): Abstract class for encryption keys. A key is "validated" if the nicknym agent has bound the user address to a - public key. Nicknym supports three different levels of key validation: - - * Level 3 - path trusted: A path of cryptographic signatures can be traced - from a trusted key to the key under evaluation. By default, only the - provider key from the user's provider is a "trusted key". - * level 2 - provider signed: The key has been signed by a provider key for - the same domain, but the provider key is not validated using a trust - path (i.e. it is only registered) - * level 1 - registered: The key has been encountered and saved, it has no - signatures (that are meaningful to the nicknym agent). + public key. """ __metaclass__ = ABCMeta @@ -176,6 +172,10 @@ class EncryptionKey(object): :return: The JSON string describing this key. :rtype: str """ + expiry_str = "" + if self.expiry_date is not None: + expiry_str = self.expiry_date.strftime("%s") + return json.dumps({ KEY_ADDRESS_KEY: self.address, KEY_TYPE_KEY: str(self.__class__), @@ -184,7 +184,7 @@ class EncryptionKey(object): KEY_DATA_KEY: self.key_data, KEY_PRIVATE_KEY: self.private, KEY_LENGTH_KEY: self.length, - KEY_EXPIRY_DATE_KEY: self.expiry_date, + KEY_EXPIRY_DATE_KEY: expiry_str, KEY_VALIDATION_KEY: str(self.validation), KEY_FIRST_SEEN_AT_KEY: self.first_seen_at, KEY_LAST_AUDITED_AT_KEY: self.last_audited_at, diff --git a/src/leap/keymanager/openpgp.py b/src/leap/keymanager/openpgp.py index e84cd297..d3c305e2 100644 --- a/src/leap/keymanager/openpgp.py +++ b/src/leap/keymanager/openpgp.py @@ -25,6 +25,7 @@ import tempfile import io +from datetime import datetime from gnupg import GPG from gnupg.gnupg import GPGUtilities @@ -37,6 +38,8 @@ from leap.keymanager.keys import ( build_key_from_dict, KEYMANAGER_KEY_TAG, TAGS_ADDRESS_PRIVATE_INDEX, + KEY_FINGERPRINT_KEY, + KEY_DATA_KEY, ) from leap.keymanager.validation import ValidationLevel @@ -176,6 +179,10 @@ def _build_key_from_gpg(address, key, key_data): :return: An instance of the key. :rtype: OpenPGPKey """ + expiry_date = None + if key['expires']: + expiry_date = datetime.fromtimestamp(int(key['expires'])) + return OpenPGPKey( address, key_id=key['keyid'], @@ -183,7 +190,7 @@ def _build_key_from_gpg(address, key, key_data): key_data=key_data, private=True if key['type'] == 'sec' else False, length=key['length'], - expiry_date=key['expires'], + expiry_date=expiry_date, validation=ValidationLevel.Weak_Chain, ) @@ -394,6 +401,16 @@ class OpenPGPScheme(EncryptionScheme): if doc is None: self._soledad.create_doc_from_json(key.get_json()) else: + if key.fingerprint == doc.content[KEY_FINGERPRINT_KEY]: + # in case of an update of the key merge them with gnupg + with self._temporary_gpgwrapper() as gpg: + gpg.import_keys(doc.content[KEY_DATA_KEY]) + gpg.import_keys(key.key_data) + gpgkey = gpg.list_keys(secret=key.private).pop() + key = _build_key_from_gpg( + key.address, gpgkey, + gpg.export_keys(gpgkey['fingerprint'], + secret=key.private)) doc.set_json(key.get_json()) self._soledad.put_doc(doc) diff --git a/src/leap/keymanager/tests/test_keymanager.py b/src/leap/keymanager/tests/test_keymanager.py index 1bd6a2e6..6a877bcf 100644 --- a/src/leap/keymanager/tests/test_keymanager.py +++ b/src/leap/keymanager/tests/test_keymanager.py @@ -81,7 +81,7 @@ class KeyManagerUtilTestCase(BaseLeapTest): 'key_data': 'key_data', 'private': 'private', 'length': 'length', - 'expiry_date': 'expiry_date', + 'expiry_date': '', 'first_seen_at': 'first_seen_at', 'last_audited_at': 'last_audited_at', 'validation': str(ValidationLevel.Weak_Chain), @@ -106,7 +106,7 @@ class KeyManagerUtilTestCase(BaseLeapTest): kdict['length'], key.length, 'Wrong data in key.') self.assertEqual( - kdict['expiry_date'], key.expiry_date, + None, key.expiry_date, 'Wrong data in key.') self.assertEqual( kdict['first_seen_at'], key.first_seen_at, diff --git a/src/leap/keymanager/tests/test_validation.py b/src/leap/keymanager/tests/test_validation.py index c7170abb..3ae873d4 100644 --- a/src/leap/keymanager/tests/test_validation.py +++ b/src/leap/keymanager/tests/test_validation.py @@ -18,6 +18,8 @@ Tests for the Validation Levels """ +from datetime import datetime + from leap.keymanager.openpgp import OpenPGPKey from leap.keymanager.errors import ( KeyNotValidUpgrade @@ -72,6 +74,13 @@ class ValidationLevelTestCase(KeyManagerWithSoledadTestCase): OpenPGPKey, validation=ValidationLevel.Provider_Trust) + def test_roll_back(self): + km = self._key_manager() + km.put_raw_key(EXPIRED_KEY_UPDATED, OpenPGPKey) + km.put_raw_key(EXPIRED_KEY, OpenPGPKey) + key = km.get_key(ADDRESS, OpenPGPKey, fetch_remote=False) + self.assertEqual(key.expiry_date, EXPIRED_KEY_NEW_EXPIRY_DATE) + # Key material for testing @@ -144,6 +153,41 @@ Osuse7+NkyUHgMXMVW7cz+nU7iO+ht2rkBtv+Z5LGlzgHTeFjKci =WhX+ -----END PGP PUBLIC KEY BLOCK----- """ +# updated expiration date +EXPIRED_KEY_NEW_EXPIRY_DATE = datetime.fromtimestamp(2045319180) +EXPIRED_KEY_UPDATED = """ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.12 (GNU/Linux) + +mQENBBvrfd0BCADGNpspaNhsbhSjKioCWrE2MTTYC+Sdpes22RabdhQyOCWvlSbj +b8p0y3kmnMOtVBT+c22/w7eu2YBfIpS4RswgE5ypr/1kZLFQueVe/cp29GjPvLwJ +82A3EOHcmXs8rSJ76h2bnkySvbJawz9rwCcaXhpdAwC+sjWvbqiwZYEL+90I4Xp3 +acDh9vNtPxDCg5RdI0bfdIEBGgHTfsda3kWGvo1wH5SgrTRq0+EcTI7aJgkMmM/A +IhnpACE52NvGdG9eB3x7xyQFsQqK8F0XvEev2UJH4SR7vb+Z7FNTJKCy6likYbSV +wGGFuowFSESnzXuUI6PcjyuO6FUbMgeM5euFABEBAAG0HExlYXAgVGVzdCBLZXkg +PGxlYXBAbGVhcC5zZT6JAT4EEwECACgCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4B +AheABQJUURIXBQld/ZovAAoJEG8V8AShiFp8xUcIALcAHZbaxvyhHRGOrwDddbH0 +fFDK0AqKTsIT7y4D/HLFCP5zG3Ck7qGPZdkHXZfzq8rIb+zUjW3oJIVI1IucHxG2 +T5kppa8RFCBAFlRWYf6R3isX3YL0d3QSragjoxRNPcHNU8ALHcvfSonFHBoi4fH4 +4rvgksAiT68SsdPaoXDlabx5T15evu/7T5e/DGMQVPMxiaSuSQhbOKuMk2wcFdmL +tBYHLZPa54hHPNhEDyxLgtKKph0gObk9ojKfH9kPvLveIcpS5CqTJfN/kqBz7CJW +wEeAi2iG3H1OEB25aCUdTxXSRNlGqEgcWPaWxtc1RzlARu7LB64OUZuRy4puiAG5 +AQ0EG+t93QEIAKqRq/2sBDW4g3FU+11LhixT+GosrfVvnitz3S9k2tBXok/wYpI1 +XeA+kTHiF0LaqoaciDRvkA9DvhDbSrNM1yeuYRyZiHlTmoPZ/Fkl60oA2cyLd1L5 +sXbuipY3TEiakugdSU4rzgi0hFycm6Go6yq2G6eC6UALvD9CTMdZHw40TadG9xpm +4thYPuJ1kPH8/bkbTi9sLHoApYgL+7ssje8w4epr0qD4IGxeKwJPf/tbTRpnd8w3 +leldixHHKAutNt49p0pkXlORAHRpUmp+KMZhFvCvIPwe9o5mYtMR7sDRxjY61ZEQ +KLyKoh5wsJsaPXBjdG7cf6G/cBcwvnQVUHcAEQEAAYkBJQQYAQIADwUCG+t93QIb +DAUJAAFRgAAKCRBvFfAEoYhafOPgB/9z4YCyT/N0262HtegHykhsyykuqEeNb1LV +D9INcP+RbCX/0IjFgP4DTMPP7qqF1OBwR276maALT321Gqxc5HN5YrwxGdmoyBLm +unaQJJlD+7B1C+jnO6r4m44obvJ/NMERxVyzkXap3J2VgRIO1wNLI9I0sH6Kj5/j +Mgy06OwXDcqIc+jB4sIJ3Tnm8LZ3phJzNEm9mI8Ak0oJ7IEcMndR6DzmRt1rJQcq +K/D7hOG02zvyRhxF27U1qR1MxeU/gNnOx8q4dnVyWB+EiV1sFl4iTOyYHEsoyd7W +Osuse7+NkyUHgMXMVW7cz+nU7iO+ht2rkBtv+Z5LGlzgHTeFjKci +=79Ll +-----END PGP PUBLIC KEY BLOCK----- +""" + import unittest if __name__ == "__main__": diff --git a/src/leap/keymanager/validation.py b/src/leap/keymanager/validation.py index 6dceb787..cf5b4a83 100644 --- a/src/leap/keymanager/validation.py +++ b/src/leap/keymanager/validation.py @@ -73,7 +73,6 @@ def can_upgrade(new_key, old_key): # An update of the same key if new_key.fingerprint == old_key.fingerprint: - # XXX wich one is newer? is that a downgrade attack? (#6210) return True # Manually verified fingerprint @@ -81,11 +80,10 @@ def can_upgrade(new_key, old_key): return True # Expired key and higher validation level - if old_key.expiry_date: - old_expiry_date = datetime.fromtimestamp(int(old_key.expiry_date)) - if (old_expiry_date < datetime.now() and - new_key.validation >= old_key.validation): - return True + if (old_key.expiry_date is not None and + old_key.expiry_date < datetime.now() and + new_key.validation >= old_key.validation): + return True # No expiration date and higher validation level elif new_key.validation >= old_key.validation: |