e6f56e2606e7bab488424927a7d4a376dca85c5b
[keymanager.git] / src / leap / keymanager / tests / test_openpgp.py
1 # -*- coding: utf-8 -*-
2 # test_keymanager.py
3 # Copyright (C) 2014 LEAP
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18
19 """
20 Tests for the OpenPGP support on Key Manager.
21 """
22
23
24 from twisted.internet.defer import inlineCallbacks
25
26 from leap.keymanager import (
27     KeyNotFound,
28     openpgp,
29 )
30 from leap.keymanager.openpgp import OpenPGPKey
31 from leap.keymanager.tests import (
32     KeyManagerWithSoledadTestCase,
33     ADDRESS,
34     ADDRESS_2,
35     KEY_FINGERPRINT,
36     PUBLIC_KEY,
37     PUBLIC_KEY_2,
38     PRIVATE_KEY,
39     PRIVATE_KEY_2,
40     GPG_BINARY_PATH
41 )
42
43
44 class OpenPGPCryptoTestCase(KeyManagerWithSoledadTestCase):
45
46     # set the trial timeout to 20min, needed by the key generation test
47     timeout = 1200
48
49     @inlineCallbacks
50     def _test_openpgp_gen_key(self):
51         pgp = openpgp.OpenPGPScheme(
52             self._soledad, gpgbinary=GPG_BINARY_PATH)
53         yield self._assert_key_not_found(pgp, 'user@leap.se')
54         key = yield pgp.gen_key('user@leap.se')
55         self.assertIsInstance(key, openpgp.OpenPGPKey)
56         self.assertEqual(
57             ['user@leap.se'], key.address, 'Wrong address bound to key.')
58         self.assertEqual(
59             4096, key.length, 'Wrong key length.')
60
61     @inlineCallbacks
62     def test_openpgp_put_delete_key(self):
63         pgp = openpgp.OpenPGPScheme(
64             self._soledad, gpgbinary=GPG_BINARY_PATH)
65         yield self._assert_key_not_found(pgp, ADDRESS)
66         yield pgp.put_ascii_key(PUBLIC_KEY, ADDRESS)
67         key = yield pgp.get_key(ADDRESS, private=False)
68         yield pgp.delete_key(key)
69         yield self._assert_key_not_found(pgp, ADDRESS)
70
71     @inlineCallbacks
72     def test_openpgp_put_ascii_key(self):
73         pgp = openpgp.OpenPGPScheme(
74             self._soledad, gpgbinary=GPG_BINARY_PATH)
75         yield self._assert_key_not_found(pgp, ADDRESS)
76         yield pgp.put_ascii_key(PUBLIC_KEY, ADDRESS)
77         key = yield pgp.get_key(ADDRESS, private=False)
78         self.assertIsInstance(key, openpgp.OpenPGPKey)
79         self.assertTrue(
80             ADDRESS in key.address, 'Wrong address bound to key.')
81         self.assertEqual(
82             4096, key.length, 'Wrong key length.')
83         yield pgp.delete_key(key)
84         yield self._assert_key_not_found(pgp, ADDRESS)
85
86     @inlineCallbacks
87     def test_get_public_key(self):
88         pgp = openpgp.OpenPGPScheme(
89             self._soledad, gpgbinary=GPG_BINARY_PATH)
90         yield self._assert_key_not_found(pgp, ADDRESS)
91         yield pgp.put_ascii_key(PUBLIC_KEY, ADDRESS)
92         yield self._assert_key_not_found(pgp, ADDRESS, private=True)
93         key = yield pgp.get_key(ADDRESS, private=False)
94         self.assertTrue(ADDRESS in key.address)
95         self.assertFalse(key.private)
96         self.assertEqual(KEY_FINGERPRINT, key.fingerprint)
97         yield pgp.delete_key(key)
98         yield self._assert_key_not_found(pgp, ADDRESS)
99
100     @inlineCallbacks
101     def test_openpgp_encrypt_decrypt(self):
102         data = 'data'
103         pgp = openpgp.OpenPGPScheme(
104             self._soledad, gpgbinary=GPG_BINARY_PATH)
105
106         # encrypt
107         yield pgp.put_ascii_key(PUBLIC_KEY, ADDRESS)
108         pubkey = yield pgp.get_key(ADDRESS, private=False)
109         cyphertext = pgp.encrypt(data, pubkey)
110
111         self.assertTrue(cyphertext is not None)
112         self.assertTrue(cyphertext != '')
113         self.assertTrue(cyphertext != data)
114         self.assertTrue(pgp.is_encrypted(cyphertext))
115         self.assertTrue(pgp.is_encrypted(cyphertext))
116
117         # decrypt
118         yield self._assert_key_not_found(pgp, ADDRESS, private=True)
119         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
120         privkey = yield pgp.get_key(ADDRESS, private=True)
121         decrypted, _ = pgp.decrypt(cyphertext, privkey)
122         self.assertEqual(decrypted, data)
123
124         yield pgp.delete_key(pubkey)
125         yield pgp.delete_key(privkey)
126         yield self._assert_key_not_found(pgp, ADDRESS, private=False)
127         yield self._assert_key_not_found(pgp, ADDRESS, private=True)
128
129     @inlineCallbacks
130     def test_verify_with_private_raises(self):
131         data = 'data'
132         pgp = openpgp.OpenPGPScheme(
133             self._soledad, gpgbinary=GPG_BINARY_PATH)
134         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
135         privkey = yield pgp.get_key(ADDRESS, private=True)
136         signed = pgp.sign(data, privkey)
137         self.assertRaises(
138             AssertionError,
139             pgp.verify, signed, privkey)
140
141     @inlineCallbacks
142     def test_sign_with_public_raises(self):
143         data = 'data'
144         pgp = openpgp.OpenPGPScheme(
145             self._soledad, gpgbinary=GPG_BINARY_PATH)
146         yield pgp.put_ascii_key(PUBLIC_KEY, ADDRESS)
147         self.assertRaises(
148             AssertionError,
149             pgp.sign, data, ADDRESS, OpenPGPKey)
150
151     @inlineCallbacks
152     def test_verify_with_wrong_key_raises(self):
153         data = 'data'
154         pgp = openpgp.OpenPGPScheme(
155             self._soledad, gpgbinary=GPG_BINARY_PATH)
156         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
157         privkey = yield pgp.get_key(ADDRESS, private=True)
158         signed = pgp.sign(data, privkey)
159         yield pgp.put_ascii_key(PUBLIC_KEY_2, ADDRESS_2)
160         wrongkey = yield pgp.get_key(ADDRESS_2)
161         self.assertFalse(pgp.verify(signed, wrongkey))
162
163     @inlineCallbacks
164     def test_encrypt_sign_with_public_raises(self):
165         data = 'data'
166         pgp = openpgp.OpenPGPScheme(
167             self._soledad, gpgbinary=GPG_BINARY_PATH)
168         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
169         privkey = yield pgp.get_key(ADDRESS, private=True)
170         pubkey = yield pgp.get_key(ADDRESS, private=False)
171         self.assertRaises(
172             AssertionError,
173             pgp.encrypt, data, privkey, sign=pubkey)
174
175     @inlineCallbacks
176     def test_decrypt_verify_with_private_raises(self):
177         data = 'data'
178         pgp = openpgp.OpenPGPScheme(
179             self._soledad, gpgbinary=GPG_BINARY_PATH)
180         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
181         privkey = yield pgp.get_key(ADDRESS, private=True)
182         pubkey = yield pgp.get_key(ADDRESS, private=False)
183         encrypted_and_signed = pgp.encrypt(
184             data, pubkey, sign=privkey)
185         self.assertRaises(
186             AssertionError,
187             pgp.decrypt,
188             encrypted_and_signed, privkey, verify=privkey)
189
190     @inlineCallbacks
191     def test_decrypt_verify_with_wrong_key(self):
192         data = 'data'
193         pgp = openpgp.OpenPGPScheme(
194             self._soledad, gpgbinary=GPG_BINARY_PATH)
195         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
196         privkey = yield pgp.get_key(ADDRESS, private=True)
197         pubkey = yield pgp.get_key(ADDRESS, private=False)
198         encrypted_and_signed = pgp.encrypt(data, pubkey, sign=privkey)
199         yield pgp.put_ascii_key(PUBLIC_KEY_2, ADDRESS_2)
200         wrongkey = yield pgp.get_key(ADDRESS_2)
201         decrypted, validsign = pgp.decrypt(encrypted_and_signed, privkey,
202                                            verify=wrongkey)
203         self.assertEqual(decrypted, data)
204         self.assertFalse(validsign)
205
206     @inlineCallbacks
207     def test_sign_verify(self):
208         data = 'data'
209         pgp = openpgp.OpenPGPScheme(
210             self._soledad, gpgbinary=GPG_BINARY_PATH)
211         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
212         privkey = yield pgp.get_key(ADDRESS, private=True)
213         signed = pgp.sign(data, privkey, detach=False)
214         pubkey = yield pgp.get_key(ADDRESS, private=False)
215         validsign = pgp.verify(signed, pubkey)
216         self.assertTrue(validsign)
217
218     @inlineCallbacks
219     def test_encrypt_sign_decrypt_verify(self):
220         pgp = openpgp.OpenPGPScheme(
221             self._soledad, gpgbinary=GPG_BINARY_PATH)
222
223         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
224         pubkey = yield pgp.get_key(ADDRESS, private=False)
225         privkey = yield pgp.get_key(ADDRESS, private=True)
226
227         yield pgp.put_ascii_key(PRIVATE_KEY_2, ADDRESS_2)
228         pubkey2 = yield pgp.get_key(ADDRESS_2, private=False)
229         privkey2 = yield pgp.get_key(ADDRESS_2, private=True)
230
231         data = 'data'
232         encrypted_and_signed = pgp.encrypt(
233             data, pubkey2, sign=privkey)
234         res, validsign = pgp.decrypt(
235             encrypted_and_signed, privkey2, verify=pubkey)
236         self.assertEqual(data, res)
237         self.assertTrue(validsign)
238
239     @inlineCallbacks
240     def test_sign_verify_detached_sig(self):
241         data = 'data'
242         pgp = openpgp.OpenPGPScheme(
243             self._soledad, gpgbinary=GPG_BINARY_PATH)
244         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
245         privkey = yield pgp.get_key(ADDRESS, private=True)
246         signature = yield pgp.sign(data, privkey, detach=True)
247         pubkey = yield pgp.get_key(ADDRESS, private=False)
248         validsign = pgp.verify(data, pubkey, detached_sig=signature)
249         self.assertTrue(validsign)
250
251     def _assert_key_not_found(self, pgp, address, private=False):
252         d = pgp.get_key(address, private=private)
253         return self.assertFailure(d, KeyNotFound)