From 3eab1813bfb9efeea65ab3ad9798b8e8dba6d163 Mon Sep 17 00:00:00 2001 From: NavaL Date: Wed, 16 Nov 2016 16:53:48 +0100 Subject: [feat] add key expiry date extension in keymanager - extends key pair (unlocked from soledad) - extension period is counted from key creation date --- bench/keymanager/common.py | 65 +++++++++++++++++++++++++ src/leap/bitmask/keymanager/__init__.py | 23 ++++++++- src/leap/bitmask/keymanager/errors.py | 6 +++ src/leap/bitmask/keymanager/openpgp.py | 41 ++++++++++++++++ src/leap/bitmask/keymanager/testing/__init__.py | 65 +++++++++++++++++++++++++ tests/integration/keymanager/common.py | 65 +++++++++++++++++++++++++ tests/integration/keymanager/test_keymanager.py | 57 +++++++++++++++++++--- tox.ini | 2 +- 8 files changed, 314 insertions(+), 10 deletions(-) diff --git a/bench/keymanager/common.py b/bench/keymanager/common.py index 6e906fa3..a7713944 100644 --- a/bench/keymanager/common.py +++ b/bench/keymanager/common.py @@ -264,3 +264,68 @@ THx7N776fcYHGumbqUMYrxrcZSbNveE6SaK8fphRam1dewM0 =a5gs -----END PGP PRIVATE KEY BLOCK----- """ + +# key with expiry date, change if key below is changed +ADDRESS_EXPIRING = 'leap.expiring@leap.se' +KEY_EXPIRING_CREATION_DATE = '2016-11-06' + +PRIVATE_EXPIRING_KEY = """ +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1 + +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 +=2Zjl +-----END PGP PRIVATE KEY BLOCK----- +""" diff --git a/src/leap/bitmask/keymanager/__init__.py b/src/leap/bitmask/keymanager/__init__.py index e3ff3b87..03ade634 100644 --- a/src/leap/bitmask/keymanager/__init__.py +++ b/src/leap/bitmask/keymanager/__init__.py @@ -38,7 +38,6 @@ from leap.bitmask.keymanager.openpgp import OpenPGPScheme class KeyManager(object): - # # server's key storage constants # @@ -110,7 +109,7 @@ class KeyManager(object): leap_ca_bundle = ca_bundle.where() if self._ca_cert_path == leap_ca_bundle: - return self._ca_cert_path # don't merge file with itself + return self._ca_cert_path # don't merge file with itself elif not self._ca_cert_path: return leap_ca_bundle @@ -711,6 +710,26 @@ class KeyManager(object): pubkey.validation = validation yield self.put_key(pubkey) + @defer.inlineCallbacks + def extend_key(self, validity='1y', passphrase=None): + """ + extend the expiration date of the key pair bound to the user's address + by the validity period, from the key's creation date. + + :param validity: new validity from creation date 'n','nw','nm' or 'ny' + where n is a number + :type validity: str + + :return: The updated secret key, with new expiry date + :rtype: OpenPGPKey + + :raise KeyExpiryExtensionError: if invalid validity period + """ + my_secret_key = yield self.get_key(self._address, private=True) + renewed_key = yield self._openpgp.extend_key(my_secret_key, validity, + passphrase) + defer.returnValue(renewed_key) + def _split_email(address): """ diff --git a/src/leap/bitmask/keymanager/errors.py b/src/leap/bitmask/keymanager/errors.py index dfff3936..1ca234de 100644 --- a/src/leap/bitmask/keymanager/errors.py +++ b/src/leap/bitmask/keymanager/errors.py @@ -88,6 +88,12 @@ class GPGError(Exception): pass +class KeyExpiryExtensionError(Exception): + """ + Error during key expiry date extension + """ + + class SignFailed(Exception): """ Raised when failed to sign. diff --git a/src/leap/bitmask/keymanager/openpgp.py b/src/leap/bitmask/keymanager/openpgp.py index a27eb3de..99e5bc72 100644 --- a/src/leap/bitmask/keymanager/openpgp.py +++ b/src/leap/bitmask/keymanager/openpgp.py @@ -616,6 +616,47 @@ class OpenPGPScheme(object): self.log.warn('Failed to encrypt: %s.' % str(e)) raise errors.EncryptError() + @defer.inlineCallbacks + def extend_key(self, seckey, validity='1y', passphrase=None): + """ + Extend C{key} key pair, expiration date for C{validity} period, + from its creation date. + + :param seckey: The secret key of the key pair to be extended. + :type seckey: OpenPGPKey + :param validity: new validity from creation date 'n','nw','nm' or 'ny' + where n is a number + :type validity: str + + :return: The updated secret key, with new expiry date + :rtype: OpenPGPKey + + :raise KeyExpiryExtensionError: Raised if failed to extend key + for some reason. + """ + leap_assert_type(seckey, OpenPGPKey) + leap_assert(seckey.private is True, 'Key is not private.') + keys = [seckey] + try: + with TempGPGWrapper(keys, self._gpgbinary) as gpg: + result = yield from_thread(gpg.extend_key, seckey.address, + validity=validity, + passphrase=passphrase) + if result.status == 'ok': + for secret in [False, True]: + fetched_key = gpg.list_keys(secret=secret).pop() + key_data = gpg.export_keys(seckey.fingerprint, + secret=secret) + renewed_key = self._build_key_from_gpg( + fetched_key, + key_data, + seckey.address) + yield self.put_key(renewed_key) + defer.returnValue(renewed_key) + except Exception as e: + logger.warn('Failed to Extend Key: %s expiration date.' % str(e)) + raise errors.KeyExpiryExtensionError(str(e)) + @defer.inlineCallbacks def decrypt(self, data, privkey, passphrase=None, verify=None): """ diff --git a/src/leap/bitmask/keymanager/testing/__init__.py b/src/leap/bitmask/keymanager/testing/__init__.py index 63ccf50a..192c7d9b 100644 --- a/src/leap/bitmask/keymanager/testing/__init__.py +++ b/src/leap/bitmask/keymanager/testing/__init__.py @@ -237,6 +237,71 @@ THx7N776fcYHGumbqUMYrxrcZSbNveE6SaK8fphRam1dewM0 -----END PGP PRIVATE KEY BLOCK----- """ +# key with expiry date, change if key below is changed +ADDRESS_EXPIRING = 'leap.expiring@leap.se' +KEY_EXPIRING_CREATION_DATE = '2016-11-06' + +PRIVATE_EXPIRING_KEY = """ +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1 + +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 +=2Zjl +-----END PGP PRIVATE KEY BLOCK----- +""" + class KeyManagerWithSoledadTestCase(unittest.TestCase, BaseLeapTest): diff --git a/tests/integration/keymanager/common.py b/tests/integration/keymanager/common.py index f120223a..9e4b9ee1 100644 --- a/tests/integration/keymanager/common.py +++ b/tests/integration/keymanager/common.py @@ -328,3 +328,68 @@ MX1BrUFh3+YWaHHNd0pQb/iBG0ZpyW+LqfAxsQN2/VC1gP1G4xM0rmtFHGi+dKX2 =AGIo -----END PGP PUBLIC KEY BLOCK----- """ + +# key with expiry date, change if key below is changed +ADDRESS_EXPIRING = 'leap.expiring@leap.se' +KEY_EXPIRING_CREATION_DATE = '2016-11-06' + +PRIVATE_EXPIRING_KEY = """ +-----BEGIN PGP PRIVATE KEY BLOCK----- +Version: GnuPG v1 + +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 +=2Zjl +-----END PGP PRIVATE KEY BLOCK----- +""" diff --git a/tests/integration/keymanager/test_keymanager.py b/tests/integration/keymanager/test_keymanager.py index 1e836a5d..466414a1 100644 --- a/tests/integration/keymanager/test_keymanager.py +++ b/tests/integration/keymanager/test_keymanager.py @@ -21,7 +21,7 @@ import json import urllib import tempfile import pkg_resources -from datetime import datetime +from datetime import datetime, timedelta from twisted.internet import defer from twisted.trial import unittest @@ -31,6 +31,7 @@ import mock from leap.common import ca_bundle from leap.bitmask.keymanager import errors +from leap.bitmask.keymanager.errors import KeyExpiryExtensionError from leap.bitmask.keymanager.keys import ( OpenPGPKey, is_address, @@ -47,18 +48,19 @@ from common import ( PUBLIC_KEY_2, PRIVATE_KEY, PRIVATE_KEY_2, + ADDRESS_EXPIRING, + KEY_EXPIRING_CREATION_DATE, + PRIVATE_EXPIRING_KEY, NEW_PUB_KEY, OLD_AND_NEW_KEY_ADDRESS ) - NICKSERVER_URI = "http://leap.se/" REMOTE_KEY_URL = "http://site.domain/key" INVALID_MAIL_ADDRESS = "notexistingemail@example.org" class KeyManagerUtilTestCase(unittest.TestCase): - def test_is_address(self): self.assertTrue( is_address('user@leap.se'), @@ -131,7 +133,6 @@ class KeyManagerUtilTestCase(unittest.TestCase): class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): - @defer.inlineCallbacks def _test_gen_key(self): km = self._key_manager() @@ -497,8 +498,8 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): self.assertEqual(expected, self._slurp_file(tmp_output.name)) def _dump_to_file(self, filename, content): - with open(filename, 'w') as out: - out.write(content) + with open(filename, 'w') as out: + out.write(content) def _slurp_file(self, filename): with open(filename) as f: @@ -552,9 +553,50 @@ class KeyManagerKeyManagementTestCase(KeyManagerWithSoledadTestCase): yield km.put_raw_key(PRIVATE_KEY, ADDRESS) km.send_key.assert_called_once_with() + @defer.inlineCallbacks + def test_keymanager_extend_key_expiry_date_for_key_pair(self): + km = self._key_manager(user=ADDRESS_EXPIRING) -class KeyManagerCryptoTestCase(KeyManagerWithSoledadTestCase): + yield km._openpgp.put_raw_key(PRIVATE_EXPIRING_KEY, ADDRESS_EXPIRING) + key = yield km.get_key(ADDRESS_EXPIRING) + + yield km.extend_key(validity='1w') + + new_expiry_date = datetime.strptime( + KEY_EXPIRING_CREATION_DATE, '%Y-%m-%d') + new_expiry_date += timedelta(weeks=1) + renewed_public_key = yield km.get_key(ADDRESS_EXPIRING) + renewed_private_key = yield km.get_key(ADDRESS_EXPIRING, private=True) + + self.assertEqual(new_expiry_date.date(), + renewed_public_key.expiry_date.date()) + self.assertEqual(new_expiry_date.date(), + renewed_private_key.expiry_date.date()) + self.assertEqual(key.fingerprint, renewed_public_key.fingerprint) + self.assertEqual(key.fingerprint, renewed_private_key.fingerprint) + + @defer.inlineCallbacks + def test_key_extension_with_invalid_period_throws_exception(self): + 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) + + 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_private_key = yield km.get_key(ADDRESS_EXPIRING, private=True) + self.assertEqual(key.expiry_date, renewed_public_key.expiry_date) + self.assertEqual(key.expiry_date, renewed_private_key.expiry_date) + self.assertEqual(key.fingerprint, renewed_public_key.fingerprint) + self.assertEqual(key.fingerprint, renewed_private_key.fingerprint) + + +class KeyManagerCryptoTestCase(KeyManagerWithSoledadTestCase): RAW_DATA = 'data' @defer.inlineCallbacks @@ -645,6 +687,7 @@ class KeyManagerCryptoTestCase(KeyManagerWithSoledadTestCase): if __name__ == "__main__": import unittest + unittest.main() # key 0F91B402: someone@somedomain.org diff --git a/tox.ini b/tox.ini index fd8f18e4..fbcc8548 100644 --- a/tox.ini +++ b/tox.ini @@ -50,7 +50,7 @@ commands = py.test -k 'not bench' --pep8 -x {posargs} deps = -r{toxinidir}/pkg/requirements-testing.pip - gnupg + -egit+https://github.com/pixelated/python-gnupg.git@feat_extend_key#egg=gnupg -e../leap_commondev -e../soledad setenv = -- cgit v1.2.3