summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrebs <drebs@leap.se>2014-11-10 16:18:17 -0200
committerdrebs <drebs@leap.se>2014-11-10 16:18:17 -0200
commit27776fbab6fe963082a882dfb5232c54b0195d5f (patch)
tree51780a96c6df649ce0245ce4c63a5fe9a530649b
parenta5cf287dabc77b7172c2f058696cee1024ea3297 (diff)
parentc223cca848e854d0015314ef517a6a4f928a2d0a (diff)
Merge remote-tracking branch 'meskio/feature/6210_key_newer' into develop
-rw-r--r--src/leap/keymanager/keys.py24
-rw-r--r--src/leap/keymanager/openpgp.py19
-rw-r--r--src/leap/keymanager/tests/test_keymanager.py4
-rw-r--r--src/leap/keymanager/tests/test_validation.py44
-rw-r--r--src/leap/keymanager/validation.py10
5 files changed, 80 insertions, 21 deletions
diff --git a/src/leap/keymanager/keys.py b/src/leap/keymanager/keys.py
index ecb0a36..a61a8c7 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 e84cd29..d3c305e 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 1bd6a2e..6a877bc 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 c7170ab..3ae873d 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 6dceb78..cf5b4a8 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: