summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomas Touceda <chiiph@leap.se>2013-05-13 10:00:39 -0300
committerTomas Touceda <chiiph@leap.se>2013-05-13 10:00:39 -0300
commit2784a01a4d12dca8ad4c66bac3125c692cee44ef (patch)
tree73ec3ef926a90a7fd5a93d9572ec476a4845e5cd
parent779afe2e830a48e91a9bda6dc8cd8b35ce555ed5 (diff)
parent8aa61059ecab25888d97aa26bcd59c0ffd09b9e9 (diff)
Merge remote-tracking branch 'drebs/feature/2488-openpgp-sign-3' into develop
-rw-r--r--changes/feature_openpgp-sign-verify1
-rw-r--r--src/leap/common/keymanager/errors.py28
-rw-r--r--src/leap/common/keymanager/openpgp.py279
-rw-r--r--src/leap/common/tests/test_keymanager.py246
4 files changed, 428 insertions, 126 deletions
diff --git a/changes/feature_openpgp-sign-verify b/changes/feature_openpgp-sign-verify
new file mode 100644
index 0000000..9422edc
--- /dev/null
+++ b/changes/feature_openpgp-sign-verify
@@ -0,0 +1 @@
+ o Add OpenPGP sign/verify
diff --git a/src/leap/common/keymanager/errors.py b/src/leap/common/keymanager/errors.py
index 1cf506e..f712975 100644
--- a/src/leap/common/keymanager/errors.py
+++ b/src/leap/common/keymanager/errors.py
@@ -25,12 +25,14 @@ class KeyNotFound(Exception):
"""
Raised when key was no found on keyserver.
"""
+ pass
class KeyAlreadyExists(Exception):
"""
Raised when attempted to create a key that already exists.
"""
+ pass
class KeyAttributesDiffer(Exception):
@@ -38,9 +40,35 @@ class KeyAttributesDiffer(Exception):
Raised when trying to delete a key but the stored key differs from the key
passed to the delete_key() method.
"""
+ pass
class NoPasswordGiven(Exception):
"""
Raised when trying to perform some action that needs a password without
providing one.
"""
+ pass
+
+class InvalidSignature(Exception):
+ """
+ Raised when signature could not be verified.
+ """
+ pass
+
+class EncryptionFailed(Exception):
+ """
+ Raised upon failures of encryption.
+ """
+ pass
+
+class DecryptionFailed(Exception):
+ """
+ Raised upon failures of decryption.
+ """
+ pass
+
+class SignFailed(Exception):
+ """
+ Raised when failed to sign.
+ """
+ pass
diff --git a/src/leap/common/keymanager/openpgp.py b/src/leap/common/keymanager/openpgp.py
index 0fd314a..0cb1308 100644
--- a/src/leap/common/keymanager/openpgp.py
+++ b/src/leap/common/keymanager/openpgp.py
@@ -29,7 +29,11 @@ from leap.common.check import leap_assert, leap_assert_type
from leap.common.keymanager.errors import (
KeyNotFound,
KeyAlreadyExists,
- KeyAttributesDiffer
+ KeyAttributesDiffer,
+ InvalidSignature,
+ EncryptionFailed,
+ DecryptionFailed,
+ SignFailed,
)
from leap.common.keymanager.keys import (
EncryptionKey,
@@ -45,84 +49,163 @@ from leap.common.keymanager.gpg import GPGWrapper
# API functions
#
-def encrypt_sym(data, passphrase):
+def encrypt_sym(data, passphrase, sign=None):
"""
- Encrypt C{data} with C{passphrase}.
+ Encrypt C{data} with C{passphrase} and sign with C{sign} private key.
@param data: The data to be encrypted.
@type data: str
@param passphrase: The passphrase used to encrypt C{data}.
@type passphrase: str
+ @param sign: The private key used for signing.
+ @type sign: OpenPGPKey
@return: The encrypted data.
@rtype: str
"""
+ leap_assert_type(passphrase, str)
+ if sign is not None:
+ leap_assert_type(sign, OpenPGPKey)
+ leap_assert(sign.private == True)
def _encrypt_cb(gpg):
- return gpg.encrypt(
- data, None, passphrase=passphrase, symmetric=True).data
-
- return _safe_call(_encrypt_cb)
-
-
-def decrypt_sym(data, passphrase):
+ result = gpg.encrypt(
+ data, None,
+ sign=sign.key_id if sign else None,
+ passphrase=passphrase, symmetric=True)
+ # Here we cannot assert for correctness of sig because the sig is in
+ # the ciphertext.
+ # result.ok - (bool) indicates if the operation succeeded
+ # result.data - (bool) contains the result of the operation
+ if result.ok is False:
+ raise EncryptionFailed('Failed to encrypt: %s' % result.stderr)
+ return result.data
+
+ return _safe_call(_encrypt_cb, [sign])
+
+
+def decrypt_sym(data, passphrase, verify=None):
"""
- Decrypt C{data} with C{passphrase}.
+ Decrypt C{data} with C{passphrase} and verify with C{verify} public
+ key.
@param data: The data to be decrypted.
@type data: str
@param passphrase: The passphrase used to decrypt C{data}.
@type passphrase: str
+ @param verify: The key used to verify a signature.
+ @type verify: OpenPGPKey
@return: The decrypted data.
@rtype: str
+
+ @raise InvalidSignature: Raised if unable to verify the signature with
+ C{verify} key.
"""
+ leap_assert_type(passphrase, str)
+ if verify is not None:
+ leap_assert_type(verify, OpenPGPKey)
+ leap_assert(verify.private == False)
def _decrypt_cb(gpg):
- return gpg.decrypt(data, passphrase=passphrase).data
-
- return _safe_call(_decrypt_cb)
-
-
-def encrypt_asym(data, key):
+ result = gpg.decrypt(data, passphrase=passphrase)
+ # result.ok - (bool) indicates if the operation succeeded
+ # result.valid - (bool) indicates if the signature was verified
+ # result.data - (bool) contains the result of the operation
+ # result.pubkey_fingerpring - (str) contains the fingerprint of the
+ # public key that signed this data.
+ if result.ok is False:
+ raise DecryptionFailed('Failed to decrypt: %s', result.stderr)
+ if verify is not None:
+ if result.valid is False or \
+ verify.fingerprint != result.pubkey_fingerprint:
+ raise InvalidSignature(
+ 'Failed to verify signature with key %s: %s' %
+ (verify.key_id, result.stderr))
+ return result.data
+
+ return _safe_call(_decrypt_cb, [verify])
+
+
+def encrypt_asym(data, pubkey, sign=None):
"""
- Encrypt C{data} using public @{key}.
+ Encrypt C{data} using public @{key} and sign with C{sign} key.
@param data: The data to be encrypted.
@type data: str
- @param key: The key used to encrypt.
- @type key: OpenPGPKey
+ @param pubkey: The key used to encrypt.
+ @type pubkey: OpenPGPKey
+ @param sign: The key used for signing.
+ @type sign: OpenPGPKey
@return: The encrypted data.
@rtype: str
"""
- leap_assert(key.private is False, 'Key is not public.')
+ leap_assert_type(pubkey, OpenPGPKey)
+ leap_assert(pubkey.private is False, 'Key is not public.')
+ if sign is not None:
+ leap_assert_type(sign, OpenPGPKey)
+ leap_assert(sign.private == True)
def _encrypt_cb(gpg):
- return gpg.encrypt(
- data, key.fingerprint, symmetric=False).data
-
- return _safe_call(_encrypt_cb, key.key_data)
-
-
-def decrypt_asym(data, key):
+ result = gpg.encrypt(
+ data, pubkey.fingerprint,
+ sign=sign.key_id if sign else None,
+ symmetric=False)
+ # Here we cannot assert for correctness of sig because the sig is in
+ # the ciphertext.
+ # result.ok - (bool) indicates if the operation succeeded
+ # result.data - (bool) contains the result of the operation
+ if result.ok is False:
+ raise EncryptionFailed(
+ 'Failed to encrypt with key %s: %s' %
+ (pubkey.key_id, result.stderr))
+ return result.data
+
+ return _safe_call(_encrypt_cb, [pubkey, sign])
+
+
+def decrypt_asym(data, privkey, verify=None):
"""
- Decrypt C{data} using private @{key}.
+ Decrypt C{data} using private @{key} and verify with C{verify} key.
@param data: The data to be decrypted.
@type data: str
- @param key: The key used to decrypt.
- @type key: OpenPGPKey
+ @param privkey: The key used to decrypt.
+ @type privkey: OpenPGPKey
+ @param verify: The key used to verify a signature.
+ @type verify: OpenPGPKey
@return: The decrypted data.
@rtype: str
+
+ @raise InvalidSignature: Raised if unable to verify the signature with
+ C{verify} key.
"""
- leap_assert(key.private is True, 'Key is not private.')
+ leap_assert(privkey.private is True, 'Key is not private.')
+ if verify is not None:
+ leap_assert_type(verify, OpenPGPKey)
+ leap_assert(verify.private == False)
def _decrypt_cb(gpg):
- return gpg.decrypt(data).data
-
- return _safe_call(_decrypt_cb, key.key_data)
+ result = gpg.decrypt(data)
+ # result.ok - (bool) indicates if the operation succeeded
+ # result.valid - (bool) indicates if the signature was verified
+ # result.data - (bool) contains the result of the operation
+ # result.pubkey_fingerpring - (str) contains the fingerprint of the
+ # public key that signed this data.
+ if result.ok is False:
+ raise DecryptionFailed('Failed to decrypt with key %s: %s' %
+ (privkey.key_id, result.stderr))
+ if verify is not None:
+ if result.valid is False or \
+ verify.fingerprint != result.pubkey_fingerprint:
+ raise InvalidSignature(
+ 'Failed to verify signature with key %s: %s' %
+ (verify.key_id, result.stderr))
+ return result.data
+
+ return _safe_call(_decrypt_cb, [privkey, verify])
def is_encrypted(data):
@@ -175,45 +258,61 @@ def is_encrypted_asym(data):
return _safe_call(_is_encrypted_cb)
-def sign(data, key):
+def sign(data, privkey):
"""
- Sign C{data} with C{key}.
+ Sign C{data} with C{privkey}.
@param data: The data to be signed.
@type data: str
- @param key: The key to be used to sign.
- @type key: OpenPGPKey
+ @param privkey: The private key to be used to sign.
+ @type privkey: OpenPGPKey
@return: The ascii-armored signed data.
@rtype: str
"""
- leap_assert_type(key, OpenPGPKey)
- leap_assert(key.private == True)
+ leap_assert_type(privkey, OpenPGPKey)
+ leap_assert(privkey.private == True)
def _sign_cb(gpg):
- return gpg.sign(data, keyid=key.key_id).data
+ result = gpg.sign(data, keyid=privkey.key_id)
+ # result.fingerprint - contains the fingerprint of the key used to
+ # sign.
+ if result.fingerprint is None:
+ raise SignFailed(
+ 'Failed to sign with key %s: %s' %
+ (privkey.key_id, result.stderr))
+ leap_assert(
+ result.fingerprint == privkey.fingerprint,
+ 'Signature and private key fingerprints mismatch: %s != %s' %
+ (result.fingerprint, privkey.fingerprint))
+ return result.data
- return _safe_call(_sign_cb, key.key_data)
+ return _safe_call(_sign_cb, [privkey])
-def verify(data, key):
+def verify(data, pubkey):
"""
- Verify signed C{data} with C{key}.
+ Verify signed C{data} with C{pubkey}.
@param data: The data to be verified.
@type data: str
- @param key: The key to be used on verification.
- @type key: OpenPGPKey
+ @param pubkey: The public key to be used on verification.
+ @type pubkey: OpenPGPKey
@return: The ascii-armored signed data.
@rtype: str
"""
- leap_assert_type(key, OpenPGPKey)
- leap_assert(key.private == False)
+ leap_assert_type(pubkey, OpenPGPKey)
+ leap_assert(pubkey.private == False)
def _verify_cb(gpg):
- return gpg.verify(data).valid
+ result = gpg.verify(data)
+ if result.valid is False or \
+ result.fingerprint != pubkey.fingerprint:
+ raise InvalidSignature(
+ 'Failed to verify signature with key %s.' % pubkey.key_id)
+ return True
- return _safe_call(_verify_cb, key.key_data)
+ return _safe_call(_verify_cb, [pubkey])
#
# Helper functions
@@ -248,35 +347,48 @@ def _build_key_from_gpg(address, key, key_data):
)
-def _build_unitary_gpgwrapper(key_data=None):
+def _build_keyring(keys=[]):
"""
- Return a temporary GPG wrapper keyring containing exactly zero or one
- keys.
- Temporary unitary keyrings allow the to use GPG's facilities for exactly
- one key. This function creates an empty temporary keyring and imports
- C{key_data} if it is not None.
+ Create an empty GPG keyring and import C{keys} into it.
+
+ @param keys: List of keys to add to the keyring.
+ @type keys: list of OpenPGPKey
- @param key_data: ASCII armored key data.
- @type key_data: str
@return: A GPG wrapper with a unitary keyring.
@rtype: gnupg.GPG
"""
+ privkeys = filter(lambda key: key.private == True, keys)
+ pubkeys = filter(lambda key: key.private == False, keys)
+ # here we filter out public keys that have a correspondent private key in
+ # the list because the private key_data by itself is enough to also have
+ # the public key in the keyring, and we want to count the keys afterwards.
+ privaddrs = map(lambda privkey: privkey.address, privkeys)
+ pubkeys = filter(lambda pubkey: pubkey.address not in privaddrs, pubkeys)
+ # create temporary dir for temporary gpg keyring
tmpdir = tempfile.mkdtemp()
gpg = GPGWrapper(gnupghome=tmpdir)
leap_assert(len(gpg.list_keys()) is 0, 'Keyring not empty.')
- if key_data:
- gpg.import_keys(key_data)
- leap_assert(
- len(gpg.list_keys()) is 1,
- 'Unitary keyring has wrong number of keys: %d.'
- % len(gpg.list_keys()))
+ # import keys into the keyring
+ gpg.import_keys(
+ reduce(
+ lambda x, y: x+y,
+ [key.key_data for key in pubkeys+privkeys], ''))
+ # assert the number of keys in the keyring
+ leap_assert(
+ len(gpg.list_keys()) == len(pubkeys)+len(privkeys),
+ 'Wrong number of public keys in keyring: %d, should be %d)' %
+ (len(gpg.list_keys()), len(pubkeys)+len(privkeys)))
+ leap_assert(
+ len(gpg.list_keys(secret=True)) == len(privkeys),
+ 'Wrong number of private keys in keyring: %d, should be %d)' %
+ (len(gpg.list_keys(secret=True)), len(privkeys)))
return gpg
-def _destroy_unitary_gpgwrapper(gpg):
+def _destroy_keyring(gpg):
"""
- Securely erase a unitary keyring.
+ Securely erase a keyring.
@param gpg: A GPG wrapper instance.
@type gpg: gnupg.GPG
@@ -292,23 +404,21 @@ def _destroy_unitary_gpgwrapper(gpg):
shutil.rmtree(gpg.gnupghome)
-def _safe_call(callback, key_data=None, **kwargs):
+def _safe_call(callback, keys=[]):
"""
- Run C{callback} in an unitary keyring containing C{key_data}.
+ Run C{callback} over a keyring containing C{keys}.
@param callback: Function whose first argument is the gpg keyring.
@type callback: function(gnupg.GPG)
- @param key_data: ASCII armored key data.
- @type key_data: str
- @param **kwargs: Other eventual parameters for the callback.
- @type **kwargs: **dict
+ @param keys: List of keys to add to the keyring.
+ @type keys: list of OpenPGPKey
@return: The results of the callback.
@rtype: str or bool
"""
- gpg = _build_unitary_gpgwrapper(key_data)
- val = callback(gpg, **kwargs)
- _destroy_unitary_gpgwrapper(gpg)
+ gpg = _build_keyring(filter(lambda key: key is not None, keys))
+ val = callback(gpg)
+ _destroy_keyring(gpg)
return val
@@ -404,18 +514,17 @@ class OpenPGPScheme(EncryptionScheme):
raise KeyNotFound(address)
return build_key_from_dict(OpenPGPKey, address, doc.content)
- def put_key_raw(self, data):
+ def put_ascii_key(self, key_data):
"""
- Put key contained in raw C{data} in local storage.
+ Put key contained in ascii-armored C{key_data} in local storage.
- @param data: The key data to be stored.
- @type data: str
+ @param key_data: The key data to be stored.
+ @type key_data: str
"""
- # TODO: add more checks for correct key data.
- leap_assert(data is not None, 'Data does not represent a key.')
-
- def _put_key_raw_cb(gpg):
+ leap_assert_type(key_data, str)
+ def _put_ascii_key_cb(gpg):
+ gpg.import_keys(key_data)
privkey = None
pubkey = None
try:
@@ -449,7 +558,7 @@ class OpenPGPScheme(EncryptionScheme):
gpg.export_keys(pubkey['fingerprint'], secret=False))
self.put_key(openpgp_pubkey)
- _safe_call(_put_key_raw_cb, data)
+ _safe_call(_put_ascii_key_cb)
def put_key(self, key):
"""
diff --git a/src/leap/common/tests/test_keymanager.py b/src/leap/common/tests/test_keymanager.py
index d3dee40..e52766a 100644
--- a/src/leap/common/tests/test_keymanager.py
+++ b/src/leap/common/tests/test_keymanager.py
@@ -51,6 +51,7 @@ from leap.common.keymanager import errors
ADDRESS = 'leap@leap.se'
+ADDRESS_2 = 'anotheruser@leap.se'
class KeyManagerUtilTestCase(BaseLeapTest):
@@ -182,15 +183,15 @@ class OpenPGPCryptoTestCase(KeyManagerWithSoledadTestCase):
def test_openpgp_put_delete_key(self):
pgp = openpgp.OpenPGPScheme(self._soledad)
self.assertRaises(KeyNotFound, pgp.get_key, ADDRESS)
- pgp.put_key_raw(PUBLIC_KEY)
+ pgp.put_ascii_key(PUBLIC_KEY)
key = pgp.get_key(ADDRESS, private=False)
pgp.delete_key(key)
self.assertRaises(KeyNotFound, pgp.get_key, ADDRESS)
- def test_openpgp_put_key_raw(self):
+ def test_openpgp_put_ascii_key(self):
pgp = openpgp.OpenPGPScheme(self._soledad)
self.assertRaises(KeyNotFound, pgp.get_key, ADDRESS)
- pgp.put_key_raw(PUBLIC_KEY)
+ pgp.put_ascii_key(PUBLIC_KEY)
key = pgp.get_key(ADDRESS, private=False)
self.assertIsInstance(key, openpgp.OpenPGPKey)
self.assertEqual(
@@ -203,7 +204,7 @@ class OpenPGPCryptoTestCase(KeyManagerWithSoledadTestCase):
def test_get_public_key(self):
pgp = openpgp.OpenPGPScheme(self._soledad)
self.assertRaises(KeyNotFound, pgp.get_key, ADDRESS)
- pgp.put_key_raw(PUBLIC_KEY)
+ pgp.put_ascii_key(PUBLIC_KEY)
self.assertRaises(
KeyNotFound, pgp.get_key, ADDRESS, private=True)
key = pgp.get_key(ADDRESS, private=False)
@@ -216,7 +217,7 @@ class OpenPGPCryptoTestCase(KeyManagerWithSoledadTestCase):
def test_openpgp_encrypt_decrypt_asym(self):
# encrypt
pgp = openpgp.OpenPGPScheme(self._soledad)
- pgp.put_key_raw(PUBLIC_KEY)
+ pgp.put_ascii_key(PUBLIC_KEY)
pubkey = pgp.get_key(ADDRESS, private=False)
cyphertext = openpgp.encrypt_asym('data', pubkey)
# assert
@@ -229,7 +230,7 @@ class OpenPGPCryptoTestCase(KeyManagerWithSoledadTestCase):
# decrypt
self.assertRaises(
KeyNotFound, pgp.get_key, ADDRESS, private=True)
- pgp.put_key_raw(PRIVATE_KEY)
+ pgp.put_ascii_key(PRIVATE_KEY)
privkey = pgp.get_key(ADDRESS, private=True)
plaintext = openpgp.decrypt_asym(cyphertext, privkey)
pgp.delete_key(pubkey)
@@ -250,13 +251,146 @@ class OpenPGPCryptoTestCase(KeyManagerWithSoledadTestCase):
plaintext = openpgp.decrypt_sym(cyphertext, 'pass')
self.assertEqual('data', plaintext)
+ def test_verify_with_private_raises(self):
+ pgp = openpgp.OpenPGPScheme(self._soledad)
+ pgp.put_ascii_key(PRIVATE_KEY)
+ data = 'data'
+ privkey = pgp.get_key(ADDRESS, private=True)
+ signed = openpgp.sign(data, privkey)
+ self.assertRaises(
+ AssertionError,
+ openpgp.verify, signed, privkey)
+
+ def test_sign_with_public_raises(self):
+ pgp = openpgp.OpenPGPScheme(self._soledad)
+ pgp.put_ascii_key(PUBLIC_KEY)
+ data = 'data'
+ pubkey = pgp.get_key(ADDRESS, private=False)
+ self.assertRaises(
+ AssertionError,
+ openpgp.sign, data, pubkey)
+
+ def test_verify_with_wrong_key_raises(self):
+ pgp = openpgp.OpenPGPScheme(self._soledad)
+ pgp.put_ascii_key(PRIVATE_KEY)
+ data = 'data'
+ privkey = pgp.get_key(ADDRESS, private=True)
+ signed = openpgp.sign(data, privkey)
+ pgp.put_ascii_key(PUBLIC_KEY_2)
+ wrongkey = pgp.get_key(ADDRESS_2)
+ self.assertRaises(
+ errors.InvalidSignature,
+ openpgp.verify, signed, wrongkey)
+
+ def test_encrypt_asym_sign_with_public_raises(self):
+ pgp = openpgp.OpenPGPScheme(self._soledad)
+ pgp.put_ascii_key(PRIVATE_KEY)
+ data = 'data'
+ privkey = pgp.get_key(ADDRESS, private=True)
+ pubkey = pgp.get_key(ADDRESS, private=False)
+ self.assertRaises(
+ AssertionError,
+ openpgp.encrypt_asym, data, privkey, sign=pubkey)
+
+ def test_encrypt_sym_sign_with_public_raises(self):
+ pgp = openpgp.OpenPGPScheme(self._soledad)
+ pgp.put_ascii_key(PUBLIC_KEY)
+ data = 'data'
+ pubkey = pgp.get_key(ADDRESS, private=False)
+ self.assertRaises(
+ AssertionError,
+ openpgp.encrypt_sym, data, '123', sign=pubkey)
+
+ def test_decrypt_asym_verify_with_private_raises(self):
+ pgp = openpgp.OpenPGPScheme(self._soledad)
+ pgp.put_ascii_key(PRIVATE_KEY)
+ data = 'data'
+ privkey = pgp.get_key(ADDRESS, private=True)
+ pubkey = pgp.get_key(ADDRESS, private=False)
+ encrypted_and_signed = openpgp.encrypt_asym(
+ data, pubkey, sign=privkey)
+ self.assertRaises(
+ AssertionError,
+ openpgp.decrypt_asym,
+ encrypted_and_signed, privkey, verify=privkey)
+
+ def test_decrypt_asym_verify_with_wrong_key_raises(self):
+ pgp = openpgp.OpenPGPScheme(self._soledad)
+ pgp.put_ascii_key(PRIVATE_KEY)
+ data = 'data'
+ privkey = pgp.get_key(ADDRESS, private=True)
+ pubkey = pgp.get_key(ADDRESS, private=False)
+ encrypted_and_signed = openpgp.encrypt_asym(data, pubkey, sign=privkey)
+ pgp.put_ascii_key(PUBLIC_KEY_2)
+ wrongkey = pgp.get_key('anotheruser@leap.se')
+ self.assertRaises(
+ errors.InvalidSignature,
+ openpgp.verify, encrypted_and_signed, wrongkey)
+
+ def test_decrypt_sym_verify_with_private_raises(self):
+ pgp = openpgp.OpenPGPScheme(self._soledad)
+ pgp.put_ascii_key(PRIVATE_KEY)
+ data = 'data'
+ privkey = pgp.get_key(ADDRESS, private=True)
+ encrypted_and_signed = openpgp.encrypt_sym(data, '123', sign=privkey)
+ self.assertRaises(
+ AssertionError,
+ openpgp.decrypt_sym,
+ encrypted_and_signed, 'decrypt', verify=privkey)
+
+ def test_decrypt_sym_verify_with_private_raises(self):
+ pgp = openpgp.OpenPGPScheme(self._soledad)
+ pgp.put_ascii_key(PRIVATE_KEY)
+ data = 'data'
+ privkey = pgp.get_key(ADDRESS, private=True)
+ encrypted_and_signed = openpgp.encrypt_sym(data, '123', sign=privkey)
+ pgp.put_ascii_key(PUBLIC_KEY_2)
+ wrongkey = pgp.get_key('anotheruser@leap.se')
+ self.assertRaises(
+ errors.InvalidSignature,
+ openpgp.verify, encrypted_and_signed, wrongkey)
+
+ def test_sign_verify(self):
+ pgp = openpgp.OpenPGPScheme(self._soledad)
+ pgp.put_ascii_key(PRIVATE_KEY)
+ data = 'data'
+ privkey = pgp.get_key(ADDRESS, private=True)
+ signed = openpgp.sign(data, privkey)
+ pubkey = pgp.get_key(ADDRESS, private=False)
+ self.assertTrue(openpgp.verify(signed, pubkey))
+
+ def test_encrypt_asym_sign_decrypt_verify(self):
+ pgp = openpgp.OpenPGPScheme(self._soledad)
+ pgp.put_ascii_key(PRIVATE_KEY)
+ pubkey = pgp.get_key(ADDRESS, private=False)
+ privkey = pgp.get_key(ADDRESS, private=True)
+ pgp.put_ascii_key(PRIVATE_KEY_2)
+ pubkey2 = pgp.get_key(ADDRESS_2, private=False)
+ privkey2 = pgp.get_key(ADDRESS_2, private=True)
+ data = 'data'
+ encrypted_and_signed = openpgp.encrypt_asym(data, pubkey2, sign=privkey)
+ res = openpgp.decrypt_asym(
+ encrypted_and_signed, privkey2, verify=pubkey)
+ self.assertTrue(data, res)
+
+ def test_encrypt_sym_sign_decrypt_verify(self):
+ pgp = openpgp.OpenPGPScheme(self._soledad)
+ pgp.put_ascii_key(PRIVATE_KEY)
+ data = 'data'
+ privkey = pgp.get_key(ADDRESS, private=True)
+ pubkey = pgp.get_key(ADDRESS, private=False)
+ encrypted_and_signed = openpgp.encrypt_sym(data, '123', sign=privkey)
+ res = openpgp.decrypt_sym(
+ encrypted_and_signed, '123', verify=pubkey)
+ self.assertEqual(data, res)
+
class KeyManagerKeyManagementTestCase(
KeyManagerWithSoledadTestCase):
def test_get_all_keys_in_db(self):
km = self._key_manager()
- km._wrapper_map[OpenPGPKey].put_key_raw(PRIVATE_KEY)
+ km._wrapper_map[OpenPGPKey].put_ascii_key(PRIVATE_KEY)
# get public keys
keys = km.get_all_keys_in_local_db(False)
self.assertEqual(len(keys), 1, 'Wrong number of keys')
@@ -270,7 +404,7 @@ class KeyManagerKeyManagementTestCase(
def test_get_public_key(self):
km = self._key_manager()
- km._wrapper_map[OpenPGPKey].put_key_raw(PRIVATE_KEY)
+ km._wrapper_map[OpenPGPKey].put_ascii_key(PRIVATE_KEY)
# get the key
key = km.get_key(ADDRESS, OpenPGPKey, private=False,
fetch_remote=False)
@@ -282,7 +416,7 @@ class KeyManagerKeyManagementTestCase(
def test_get_private_key(self):
km = self._key_manager()
- km._wrapper_map[OpenPGPKey].put_key_raw(PRIVATE_KEY)
+ km._wrapper_map[OpenPGPKey].put_ascii_key(PRIVATE_KEY)
# get the key
key = km.get_key(ADDRESS, OpenPGPKey, private=True,
fetch_remote=False)
@@ -300,7 +434,7 @@ class KeyManagerKeyManagementTestCase(
def test_send_private_key_raises_key_not_found(self):
km = self._key_manager()
- km._wrapper_map[OpenPGPKey].put_key_raw(PUBLIC_KEY)
+ km._wrapper_map[OpenPGPKey].put_ascii_key(PUBLIC_KEY)
self.assertRaises(
KeyNotFound,
km.send_key, OpenPGPKey, send_private=True,
@@ -308,14 +442,14 @@ class KeyManagerKeyManagementTestCase(
def test_send_private_key_without_password_raises(self):
km = self._key_manager()
- km._wrapper_map[OpenPGPKey].put_key_raw(PUBLIC_KEY)
+ km._wrapper_map[OpenPGPKey].put_ascii_key(PUBLIC_KEY)
self.assertRaises(
NoPasswordGiven,
km.send_key, OpenPGPKey, send_private=True)
def test_send_public_key(self):
km = self._key_manager()
- km._wrapper_map[OpenPGPKey].put_key_raw(PUBLIC_KEY)
+ km._wrapper_map[OpenPGPKey].put_ascii_key(PUBLIC_KEY)
km._fetcher.put = mock.Mock()
km.token = '123'
km.send_key(OpenPGPKey, send_private=False)
@@ -356,41 +490,13 @@ class KeyManagerKeyManagementTestCase(
def test_refresh_keys(self):
# TODO: maybe we should not attempt to refresh our own public key?
km = self._key_manager()
- km._wrapper_map[OpenPGPKey].put_key_raw(PUBLIC_KEY)
+ km._wrapper_map[OpenPGPKey].put_ascii_key(PUBLIC_KEY)
km.fetch_keys_from_server = mock.Mock(return_value=[])
km.refresh_keys()
km.fetch_keys_from_server.assert_called_once_with(
'leap@leap.se'
)
- def test_verify_with_private_raises(self):
- km = self._key_manager()
- km._wrapper_map[OpenPGPKey].put_key_raw(PRIVATE_KEY)
- data = 'data'
- privkey = km.get_key(ADDRESS, OpenPGPKey, private=True)
- signed = openpgp.sign(data, privkey)
- self.assertRaises(
- AssertionError,
- openpgp.verify, signed, privkey)
-
- def test_sign_with_public_raises(self):
- km = self._key_manager()
- km._wrapper_map[OpenPGPKey].put_key_raw(PUBLIC_KEY)
- data = 'data'
- pubkey = km.get_key(ADDRESS, OpenPGPKey, private=False)
- self.assertRaises(
- AssertionError,
- openpgp.sign, data, pubkey)
-
- def test_sign_verify(self):
- km = self._key_manager()
- km._wrapper_map[OpenPGPKey].put_key_raw(PRIVATE_KEY)
- data = 'data'
- privkey = km.get_key(ADDRESS, OpenPGPKey, private=True)
- signed = openpgp.sign(data, privkey)
- pubkey = km.get_key(ADDRESS, OpenPGPKey, private=False)
- self.assertTrue(openpgp.verify(signed, pubkey))
-
# Key material for testing
KEY_FINGERPRINT = "E36E738D69173C13D709E44F2F455E2824D18DDF"
@@ -554,3 +660,61 @@ RZXoH+FTg9UAW87eqU610npOkT6cRaBxaMK/mDtGNdc=
=JTFu
-----END PGP PRIVATE KEY BLOCK-----
"""
+
+PUBLIC_KEY_2 = """
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.10 (GNU/Linux)
+
+mI0EUYwJXgEEAMbTKHuPJ5/Gk34l9Z06f+0WCXTDXdte1UBoDtZ1erAbudgC4MOR
+gquKqoj3Hhw0/ILqJ88GcOJmKK/bEoIAuKaqlzDF7UAYpOsPZZYmtRfPC2pTCnXq
+Z1vdeqLwTbUspqXflkCkFtfhGKMq5rH8GV5a3tXZkRWZhdNwhVXZagC3ABEBAAG0
+IWFub3RoZXJ1c2VyIDxhbm90aGVydXNlckBsZWFwLnNlPoi4BBMBAgAiBQJRjAle
+AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRB/nfpof+5XWotuA/4tLN4E
+gUr7IfLy2HkHAxzw7A4rqfMN92DIM9mZrDGaWRrOn3aVF7VU1UG7MDkHfPvp/cFw
+ezoCw4s4IoHVc/pVlOkcHSyt4/Rfh248tYEJmFCJXGHpkK83VIKYJAithNccJ6Q4
+JE/o06Mtf4uh/cA1HUL4a4ceqUhtpLJULLeKo7iNBFGMCV4BBADsyQI7GR0wSAxz
+VayLjuPzgT+bjbFeymIhjuxKIEwnIKwYkovztW+4bbOcQs785k3Lp6RzvigTpQQt
+Z/hwcLOqZbZw8t/24+D+Pq9mMP2uUvCFFqLlVvA6D3vKSQ/XNN+YB919WQ04jh63
+yuRe94WenT1RJd6xU1aaUff4rKizuQARAQABiJ8EGAECAAkFAlGMCV4CGwwACgkQ
+f536aH/uV1rPZQQAqCzRysOlu8ez7PuiBD4SebgRqWlxa1TF1ujzfLmuPivROZ2X
+Kw5aQstxgGSjoB7tac49s0huh4X8XK+BtJBfU84JS8Jc2satlfwoyZ35LH6sDZck
+I+RS/3we6zpMfHs3vvp9xgca6ZupQxivGtxlJs294TpJorx+mFFqbV17AzQ=
+=Thdu
+-----END PGP PUBLIC KEY BLOCK-----
+"""
+
+PRIVATE_KEY_2 = """
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1.4.10 (GNU/Linux)
+
+lQHYBFGMCV4BBADG0yh7jyefxpN+JfWdOn/tFgl0w13bXtVAaA7WdXqwG7nYAuDD
+kYKriqqI9x4cNPyC6ifPBnDiZiiv2xKCALimqpcwxe1AGKTrD2WWJrUXzwtqUwp1
+6mdb3Xqi8E21LKal35ZApBbX4RijKuax/BleWt7V2ZEVmYXTcIVV2WoAtwARAQAB
+AAP7BLuSAx7tOohnimEs74ks8l/L6dOcsFQZj2bqs4AoY3jFe7bV0tHr4llypb/8
+H3/DYvpf6DWnCjyUS1tTnXSW8JXtx01BUKaAufSmMNg9blKV6GGHlT/Whe9uVyks
+7XHk/+9mebVMNJ/kNlqq2k+uWqJohzC8WWLRK+d1tBeqDsECANZmzltPaqUsGV5X
+C3zszE3tUBgptV/mKnBtopKi+VH+t7K6fudGcG+bAcZDUoH/QVde52mIIjjIdLje
+uajJuHUCAO1mqh+vPoGv4eBLV7iBo3XrunyGXiys4a39eomhxTy3YktQanjjx+ty
+GltAGCs5PbWGO6/IRjjvd46wh53kzvsCAO0J97gsWhzLuFnkxFAJSPk7RRlyl7lI
+1XS/x0Og6j9XHCyY1OYkfBm0to3UlCfkgirzCYlTYObCofzdKFIPDmSqHbQhYW5v
+dGhlcnVzZXIgPGFub3RoZXJ1c2VyQGxlYXAuc2U+iLgEEwECACIFAlGMCV4CGwMG
+CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEH+d+mh/7ldai24D/i0s3gSBSvsh
+8vLYeQcDHPDsDiup8w33YMgz2ZmsMZpZGs6fdpUXtVTVQbswOQd8++n9wXB7OgLD
+izgigdVz+lWU6RwdLK3j9F+Hbjy1gQmYUIlcYemQrzdUgpgkCK2E1xwnpDgkT+jT
+oy1/i6H9wDUdQvhrhx6pSG2kslQst4qjnQHYBFGMCV4BBADsyQI7GR0wSAxzVayL
+juPzgT+bjbFeymIhjuxKIEwnIKwYkovztW+4bbOcQs785k3Lp6RzvigTpQQtZ/hw
+cLOqZbZw8t/24+D+Pq9mMP2uUvCFFqLlVvA6D3vKSQ/XNN+YB919WQ04jh63yuRe
+94WenT1RJd6xU1aaUff4rKizuQARAQABAAP9EyElqJ3dq3EErXwwT4mMnbd1SrVC
+rUJrNWQZL59mm5oigS00uIyR0SvusOr+UzTtd8ysRuwHy5d/LAZsbjQStaOMBILx
+77TJveOel0a1QK0YSMF2ywZMCKvquvjli4hAtWYz/EwfuzQN3t23jc5ny+GqmqD2
+3FUxLJosFUfLNmECAO9KhVmJi+L9dswIs+2Dkjd1eiRQzNOEVffvYkGYZyKxNiXF
+UA5kvyZcB4iAN9sWCybE4WHZ9jd4myGB0MPDGxkCAP1RsXJbbuD6zS7BXe5gwunO
+2q4q7ptdSl/sJYQuTe1KNP5d/uGsvlcFfsYjpsopasPjFBIncc/2QThMKlhoEaEB
+/0mVAxpT6SrEvUbJ18z7kna24SgMPr3OnPMxPGfvNLJY/Xv/A17YfoqjmByCvsKE
+JCDjopXtmbcrZyoEZbEht9mko4ifBBgBAgAJBQJRjAleAhsMAAoJEH+d+mh/7lda
+z2UEAKgs0crDpbvHs+z7ogQ+Enm4EalpcWtUxdbo83y5rj4r0TmdlysOWkLLcYBk
+o6Ae7WnOPbNIboeF/FyvgbSQX1POCUvCXNrGrZX8KMmd+Sx+rA2XJCPkUv98Hus6
+THx7N776fcYHGumbqUMYrxrcZSbNveE6SaK8fphRam1dewM0
+=a5gs
+-----END PGP PRIVATE KEY BLOCK-----
+"""