From e5c567d79557eecbd708f4fabe8d04c92cf66ea1 Mon Sep 17 00:00:00 2001 From: NavaL Date: Fri, 18 Nov 2016 20:22:14 +0100 Subject: [feat] first phase of key regeneration - if current key pair is expired, it'll be extended for a day first - new key pair will be signed by the old key --- src/leap/bitmask/keymanager/__init__.py | 19 +++++++++++++++ src/leap/bitmask/keymanager/keys.py | 3 +++ src/leap/bitmask/keymanager/openpgp.py | 42 ++++++++++++++++++++++++++++++--- 3 files changed, 61 insertions(+), 3 deletions(-) (limited to 'src/leap') diff --git a/src/leap/bitmask/keymanager/__init__.py b/src/leap/bitmask/keymanager/__init__.py index 03ade634..483c7e51 100644 --- a/src/leap/bitmask/keymanager/__init__.py +++ b/src/leap/bitmask/keymanager/__init__.py @@ -330,6 +330,25 @@ class KeyManager(object): d.addCallback(signal_finished) return d + def regenerate_key(self): + """ + Regenerate a key bound to the user's address. + + :return: A Deferred which fires with the generated EncryptionKey. + :rtype: Deferred + """ + + def signal_finished(key): + emit_async( + catalog.KEYMANAGER_FINISHED_KEY_GENERATION, self._address) + return key + self.log.info('Regenerating key for %s.' % self._address) + emit_async(catalog.KEYMANAGER_STARTED_KEY_GENERATION, self._address) + + d = self._openpgp.regenerate_key(self._address) + d.addCallback(signal_finished) + return d + # # Setters/getters # diff --git a/src/leap/bitmask/keymanager/keys.py b/src/leap/bitmask/keymanager/keys.py index 54609c05..d37c6d21 100644 --- a/src/leap/bitmask/keymanager/keys.py +++ b/src/leap/bitmask/keymanager/keys.py @@ -283,6 +283,9 @@ class OpenPGPKey(object): value = str(value) return key, value + def has_expired(self): + return self.expiry_date < datetime.now() + def __iter__(self): return self diff --git a/src/leap/bitmask/keymanager/openpgp.py b/src/leap/bitmask/keymanager/openpgp.py index 99e5bc72..d0acca54 100644 --- a/src/leap/bitmask/keymanager/openpgp.py +++ b/src/leap/bitmask/keymanager/openpgp.py @@ -22,10 +22,8 @@ Infrastructure for using OpenPGP keys in Key Manager. import os import re import tempfile -import traceback import io - from datetime import datetime from multiprocessing import cpu_count from twisted.internet import defer @@ -162,6 +160,41 @@ class OpenPGPScheme(object): # # Keys management # + @defer.inlineCallbacks + def regenerate_key(self, address): + """ + Deactivate Current keypair, + Generate a new OpenPGP keypair bound to C{address}, + and sign the new key with the old key. + + :param address: The address bound to the key. + :type address: str + + :return: A Deferred which fires with the new key bound to address. + :rtype: Deferred + """ + leap_assert(is_address(address), 'Not an user address: %s' % address) + current_sec_key = yield self.get_key(address, private=True) + with TempGPGWrapper([current_sec_key], self._gpgbinary) as gpg: + if current_sec_key.has_expired(): + temporary_extension_period = '1' # extend for 1 extra day + gpg.extend_key(current_sec_key.fingerprint, + validity=temporary_extension_period) + yield self.unactivate_key(address) + new_key = yield self.gen_key(address) + gpg.import_keys(new_key.key_data) + key_signing = yield from_thread(gpg.sign_key, new_key.fingerprint) + if key_signing.status == 'ok': + fetched_keys = gpg.list_keys(secret=False) + fetched_key = filter(lambda k: k['fingerprint'] == + new_key.fingerprint, fetched_keys)[0] + key_data = gpg.export_keys(new_key.fingerprint, secret=False) + renewed_key = self._build_key_from_gpg( + fetched_key, + key_data, + new_key.address) + yield self.put_key(renewed_key) + defer.returnValue(new_key) def gen_key(self, address): """ @@ -382,6 +415,7 @@ class OpenPGPScheme(object): :return: A Deferred which fires when the key is in the storage. :rtype: Deferred """ + def merge_and_put((keydoc, activedoc)): if not keydoc: return put_new_key(activedoc) @@ -440,6 +474,7 @@ class OpenPGPScheme(object): (keydoc, activedoc) or None if it does not exist. :rtype: Deferred """ + def get_key_from_active_doc(activedoc): if not activedoc: return (None, None) @@ -654,7 +689,7 @@ class OpenPGPScheme(object): 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)) + log.warn('Failed to Extend Key: %s expiration date.' % str(e)) raise errors.KeyExpiryExtensionError(str(e)) @defer.inlineCallbacks @@ -844,6 +879,7 @@ class OpenPGPScheme(object): the deletions are completed :rtype: Deferred """ + def log_key_doc(doc): self.log.error("\t%s: %s" % (doc.content[KEY_UIDS_KEY], doc.content[KEY_FINGERPRINT_KEY])) -- cgit v1.2.3