From 314bc876d564cd6265cc8eb4095e423f1140349a Mon Sep 17 00:00:00 2001 From: drebs Date: Mon, 15 Apr 2013 10:41:56 -0300 Subject: Add basic openpgp key handling to Key Manager --- src/leap/common/keymanager/keys.py | 127 +++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 src/leap/common/keymanager/keys.py (limited to 'src/leap/common/keymanager/keys.py') diff --git a/src/leap/common/keymanager/keys.py b/src/leap/common/keymanager/keys.py new file mode 100644 index 0000000..13e3c0b --- /dev/null +++ b/src/leap/common/keymanager/keys.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- +# keys.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +""" +Abstact key type and wrapper representations. +""" + + +from abc import ABCMeta, abstractmethod + + +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). + """ + + __metaclass__ = ABCMeta + + def __init__(self, address, key_id=None, fingerprint=None, + key_data=None, length=None, expiry_date=None, + validation=None, first_seen_at=None, + last_audited_at=None): + self.address = address + self.key_id = key_id + self.fingerprint = fingerprint + self.key_data = key_data + self.length = length + self.expiry_date = expiry_date + self.validation = validation + self.first_seen_at = first_seen_at + self.last_audited_at = last_audited_at + + def get_json(self): + """ + Return a JSON string describing this key. + + @return: The JSON string describing this key. + @rtype: str + """ + return json.dumps({ + 'address': self.address, + 'type': str(self.__type__), + 'key_id': self.key_id, + 'fingerprint': self.fingerprint, + 'key_data': self.key_data, + 'length': self.length, + 'expiry_date': self.expiry_date, + 'validation': self.validation, + 'first_seen_at': self.first_seen_at, + 'last_audited_at': self.last_audited_at, + }) + + +# +# Key wrappers +# + +class KeyTypeWrapper(object): + """ + Abstract class for Key Type Wrappers. + + A wrapper for a certain key type should know how to get and put keys in + local storage using Soledad and also how to generate new keys. + """ + + __metaclass__ = ABCMeta + + @abstractmethod + def get_key(self, address): + """ + Get key from local storage. + + @param address: The address bound to the key. + @type address: str + + @return: The key bound to C{address}. + @rtype: EncryptionKey + @raise KeyNotFound: If the key was not found on local storage. + """ + + @abstractmethod + def put_key(self, key): + """ + Put a key in local storage. + + @param key: The key to be stored. + @type key: EncryptionKey + """ + + @abstractmethod + def gen_key(self, address): + """ + Generate a new key. + + @param address: The address bound to the key. + @type address: str + @return: The key bound to C{address}. + @rtype: EncryptionKey + """ + -- cgit v1.2.3 From b833d9042da3a1650fde3354f38998a2e497672b Mon Sep 17 00:00:00 2001 From: drebs Date: Fri, 19 Apr 2013 21:48:57 -0300 Subject: Make keymanager OpenPGP wrapper store using Soledad. --- src/leap/common/keymanager/keys.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'src/leap/common/keymanager/keys.py') diff --git a/src/leap/common/keymanager/keys.py b/src/leap/common/keymanager/keys.py index 13e3c0b..2e1ed89 100644 --- a/src/leap/common/keymanager/keys.py +++ b/src/leap/common/keymanager/keys.py @@ -21,6 +21,12 @@ Abstact key type and wrapper representations. """ +try: + import simplejson as json +except ImportError: + import json # noqa + + from abc import ABCMeta, abstractmethod @@ -44,13 +50,13 @@ class EncryptionKey(object): __metaclass__ = ABCMeta def __init__(self, address, key_id=None, fingerprint=None, - key_data=None, length=None, expiry_date=None, - validation=None, first_seen_at=None, - last_audited_at=None): + key_data=None, private=None, length=None, expiry_date=None, + validation=None, first_seen_at=None, last_audited_at=None): self.address = address self.key_id = key_id self.fingerprint = fingerprint self.key_data = key_data + self.private = private self.length = length self.expiry_date = expiry_date self.validation = validation @@ -66,10 +72,11 @@ class EncryptionKey(object): """ return json.dumps({ 'address': self.address, - 'type': str(self.__type__), + 'type': str(self.__class__), 'key_id': self.key_id, 'fingerprint': self.fingerprint, 'key_data': self.key_data, + 'private': self.private, 'length': self.length, 'expiry_date': self.expiry_date, 'validation': self.validation, @@ -92,6 +99,15 @@ class KeyTypeWrapper(object): __metaclass__ = ABCMeta + def __init__(self, soledad): + """ + Initialize the Key Type Wrapper. + + @param soledad: A Soledad instance for local storage of keys. + @type soledad: leap.soledad.Soledad + """ + self._soledad = soledad + @abstractmethod def get_key(self, address): """ @@ -124,4 +140,3 @@ class KeyTypeWrapper(object): @return: The key bound to C{address}. @rtype: EncryptionKey """ - -- cgit v1.2.3 From b3ad976ec8aa64a00cc824dc57aa2135ab41deb6 Mon Sep 17 00:00:00 2001 From: drebs Date: Mon, 22 Apr 2013 10:39:58 -0300 Subject: Add send_keys() and refresh_keys() to Key Manager. --- src/leap/common/keymanager/keys.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/leap/common/keymanager/keys.py') diff --git a/src/leap/common/keymanager/keys.py b/src/leap/common/keymanager/keys.py index 2e1ed89..bed407c 100644 --- a/src/leap/common/keymanager/keys.py +++ b/src/leap/common/keymanager/keys.py @@ -109,12 +109,14 @@ class KeyTypeWrapper(object): self._soledad = soledad @abstractmethod - def get_key(self, address): + def get_key(self, address, private=False): """ Get key from local storage. @param address: The address bound to the key. @type address: str + @param private: Look for a private key instead of a public one? + @type private: bool @return: The key bound to C{address}. @rtype: EncryptionKey -- cgit v1.2.3 From 62b5a7798924188ba915a1c095917d8709e20ae7 Mon Sep 17 00:00:00 2001 From: drebs Date: Tue, 23 Apr 2013 20:50:02 -0300 Subject: Refactor, fixes, add api, tests. * Change KeyTypeWrapper to EncryptionScheme * Change OpenPGPWrapper to OpenPGPScheme * Add missing and standardized crypto API. * Add delete_key() * Fix put_key raw so it puts either public or private keys. * Fix gpg's is_encrypted() * Fix openpgp's safe callbacks so they return correctly. * Remove binascii because it generates invalid doc ids. * Add tests. --- src/leap/common/keymanager/keys.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'src/leap/common/keymanager/keys.py') diff --git a/src/leap/common/keymanager/keys.py b/src/leap/common/keymanager/keys.py index bed407c..250c2fa 100644 --- a/src/leap/common/keymanager/keys.py +++ b/src/leap/common/keymanager/keys.py @@ -17,7 +17,7 @@ """ -Abstact key type and wrapper representations. +Abstact key type and encryption scheme representations. """ @@ -86,22 +86,23 @@ class EncryptionKey(object): # -# Key wrappers +# Encryption schemes # -class KeyTypeWrapper(object): +class EncryptionScheme(object): """ - Abstract class for Key Type Wrappers. + Abstract class for Encryption Schemes. - A wrapper for a certain key type should know how to get and put keys in - local storage using Soledad and also how to generate new keys. + A wrapper for a certain encryption schemes should know how to get and put + keys in local storage using Soledad, how to generate new keys and how to + find out about possibly encrypted content. """ __metaclass__ = ABCMeta def __init__(self, soledad): """ - Initialize the Key Type Wrapper. + Initialize this Encryption Scheme. @param soledad: A Soledad instance for local storage of keys. @type soledad: leap.soledad.Soledad @@ -139,6 +140,16 @@ class KeyTypeWrapper(object): @param address: The address bound to the key. @type address: str + @return: The key bound to C{address}. @rtype: EncryptionKey """ + + @abstractmethod + def delete_key(self, key): + """ + Remove C{key} from storage. + + @param key: The key to be removed. + @type key: EncryptionKey + """ -- cgit v1.2.3 From 4113dd985b9b5fc3b8e9839670ac5f7416f3f634 Mon Sep 17 00:00:00 2001 From: drebs Date: Sat, 27 Apr 2013 00:06:01 -0300 Subject: Add key refreshing for KeyManager. --- src/leap/common/keymanager/keys.py | 71 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'src/leap/common/keymanager/keys.py') diff --git a/src/leap/common/keymanager/keys.py b/src/leap/common/keymanager/keys.py index 250c2fa..453e0ed 100644 --- a/src/leap/common/keymanager/keys.py +++ b/src/leap/common/keymanager/keys.py @@ -25,11 +25,81 @@ try: import simplejson as json except ImportError: import json # noqa +import re +from hashlib import sha256 from abc import ABCMeta, abstractmethod +from leap.common.check import leap_assert +# +# Key handling utilities +# + +def is_address(address): + """ + Return whether the given C{address} is in the form user@provider. + + @param address: The address to be tested. + @type address: str + @return: Whether C{address} is in the form user@provider. + @rtype: bool + """ + return bool(re.match('[\w.-]+@[\w.-]+', address)) + + +def build_key_from_dict(kClass, address, kdict): + """ + Build an C{kClass} key bound to C{address} based on info in C{kdict}. + + @param address: The address bound to the key. + @type address: str + @param kdict: Dictionary with key data. + @type kdict: dict + @return: An instance of the key. + @rtype: C{kClass} + """ + leap_assert(address == kdict['address'], 'Wrong address in key data.') + return kClass( + address, + key_id=kdict['key_id'], + fingerprint=kdict['fingerprint'], + key_data=kdict['key_data'], + private=kdict['private'], + length=kdict['length'], + expiry_date=kdict['expiry_date'], + first_seen_at=kdict['first_seen_at'], + last_audited_at=kdict['last_audited_at'], + validation=kdict['validation'], # TODO: verify for validation. + ) + + +def keymanager_doc_id(ktype, address, private=False): + """ + Return the document id for the document containing a key for + C{address}. + + @param address: The type of the key. + @type address: KeyType + @param address: The address bound to the key. + @type address: str + @param private: Whether the key is private or not. + @type private: bool + @return: The document id for the document that stores a key bound to + C{address}. + @rtype: str + """ + leap_assert(is_address(address), "Wrong address format: %s" % address) + ktype = str(ktype) + visibility = 'private' if private else 'public' + return sha256('keymanager-'+address+'-'+ktype+'-'+visibility).hexdigest() + + +# +# Abstraction for encryption keys +# + class EncryptionKey(object): """ Abstract class for encryption keys. @@ -82,6 +152,7 @@ class EncryptionKey(object): 'validation': self.validation, 'first_seen_at': self.first_seen_at, 'last_audited_at': self.last_audited_at, + 'tags': ['keymanager-key'], }) -- cgit v1.2.3 From 170cd90f593a106ea7730babde310724410a585e Mon Sep 17 00:00:00 2001 From: Tomas Touceda Date: Thu, 2 May 2013 15:02:33 -0300 Subject: Various fixes --- src/leap/common/keymanager/keys.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/leap/common/keymanager/keys.py') diff --git a/src/leap/common/keymanager/keys.py b/src/leap/common/keymanager/keys.py index 453e0ed..2e6bfe9 100644 --- a/src/leap/common/keymanager/keys.py +++ b/src/leap/common/keymanager/keys.py @@ -194,6 +194,7 @@ class EncryptionScheme(object): @rtype: EncryptionKey @raise KeyNotFound: If the key was not found on local storage. """ + pass @abstractmethod def put_key(self, key): @@ -203,6 +204,7 @@ class EncryptionScheme(object): @param key: The key to be stored. @type key: EncryptionKey """ + pass @abstractmethod def gen_key(self, address): @@ -215,6 +217,7 @@ class EncryptionScheme(object): @return: The key bound to C{address}. @rtype: EncryptionKey """ + pass @abstractmethod def delete_key(self, key): @@ -224,3 +227,4 @@ class EncryptionScheme(object): @param key: The key to be removed. @type key: EncryptionKey """ + pass -- cgit v1.2.3