Find the gpg path instead of hard code it
[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 )
41
42
43 class OpenPGPCryptoTestCase(KeyManagerWithSoledadTestCase):
44
45     # set the trial timeout to 20min, needed by the key generation test
46     timeout = 1200
47
48     @inlineCallbacks
49     def _test_openpgp_gen_key(self):
50         pgp = openpgp.OpenPGPScheme(
51             self._soledad, gpgbinary=self.gpg_binary_path)
52         yield self._assert_key_not_found(pgp, 'user@leap.se')
53         key = yield pgp.gen_key('user@leap.se')
54         self.assertIsInstance(key, openpgp.OpenPGPKey)
55         self.assertEqual(
56             ['user@leap.se'], key.address, 'Wrong address bound to key.')
57         self.assertEqual(
58             4096, key.length, 'Wrong key length.')
59
60     @inlineCallbacks
61     def test_openpgp_put_delete_key(self):
62         pgp = openpgp.OpenPGPScheme(
63             self._soledad, gpgbinary=self.gpg_binary_path)
64         yield self._assert_key_not_found(pgp, ADDRESS)
65         yield pgp.put_ascii_key(PUBLIC_KEY, ADDRESS)
66         key = yield pgp.get_key(ADDRESS, private=False)
67         yield pgp.delete_key(key)
68         yield self._assert_key_not_found(pgp, ADDRESS)
69
70     @inlineCallbacks
71     def test_openpgp_put_ascii_key(self):
72         pgp = openpgp.OpenPGPScheme(
73             self._soledad, gpgbinary=self.gpg_binary_path)
74         yield self._assert_key_not_found(pgp, ADDRESS)
75         yield pgp.put_ascii_key(PUBLIC_KEY, ADDRESS)
76         key = yield pgp.get_key(ADDRESS, private=False)
77         self.assertIsInstance(key, openpgp.OpenPGPKey)
78         self.assertTrue(
79             ADDRESS in key.address, 'Wrong address bound to key.')
80         self.assertEqual(
81             4096, key.length, 'Wrong key length.')
82         yield pgp.delete_key(key)
83         yield self._assert_key_not_found(pgp, ADDRESS)
84
85     @inlineCallbacks
86     def test_get_public_key(self):
87         pgp = openpgp.OpenPGPScheme(
88             self._soledad, gpgbinary=self.gpg_binary_path)
89         yield self._assert_key_not_found(pgp, ADDRESS)
90         yield pgp.put_ascii_key(PUBLIC_KEY, ADDRESS)
91         yield self._assert_key_not_found(pgp, ADDRESS, private=True)
92         key = yield pgp.get_key(ADDRESS, private=False)
93         self.assertTrue(ADDRESS in key.address)
94         self.assertFalse(key.private)
95         self.assertEqual(KEY_FINGERPRINT, key.fingerprint)
96         yield pgp.delete_key(key)
97         yield self._assert_key_not_found(pgp, ADDRESS)
98
99     @inlineCallbacks
100     def test_openpgp_encrypt_decrypt(self):
101         data = 'data'
102         pgp = openpgp.OpenPGPScheme(
103             self._soledad, gpgbinary=self.gpg_binary_path)
104
105         # encrypt
106         yield pgp.put_ascii_key(PUBLIC_KEY, ADDRESS)
107         pubkey = yield pgp.get_key(ADDRESS, private=False)
108         cyphertext = pgp.encrypt(data, pubkey)
109
110         self.assertTrue(cyphertext is not None)
111         self.assertTrue(cyphertext != '')
112         self.assertTrue(cyphertext != data)
113         self.assertTrue(pgp.is_encrypted(cyphertext))
114         self.assertTrue(pgp.is_encrypted(cyphertext))
115
116         # decrypt
117         yield self._assert_key_not_found(pgp, ADDRESS, private=True)
118         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
119         privkey = yield pgp.get_key(ADDRESS, private=True)
120         decrypted, _ = pgp.decrypt(cyphertext, privkey)
121         self.assertEqual(decrypted, data)
122
123         yield pgp.delete_key(pubkey)
124         yield pgp.delete_key(privkey)
125         yield self._assert_key_not_found(pgp, ADDRESS, private=False)
126         yield self._assert_key_not_found(pgp, ADDRESS, private=True)
127
128     @inlineCallbacks
129     def test_verify_with_private_raises(self):
130         data = 'data'
131         pgp = openpgp.OpenPGPScheme(
132             self._soledad, gpgbinary=self.gpg_binary_path)
133         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
134         privkey = yield pgp.get_key(ADDRESS, private=True)
135         signed = pgp.sign(data, privkey)
136         self.assertRaises(
137             AssertionError,
138             pgp.verify, signed, privkey)
139
140     @inlineCallbacks
141     def test_sign_with_public_raises(self):
142         data = 'data'
143         pgp = openpgp.OpenPGPScheme(
144             self._soledad, gpgbinary=self.gpg_binary_path)
145         yield pgp.put_ascii_key(PUBLIC_KEY, ADDRESS)
146         self.assertRaises(
147             AssertionError,
148             pgp.sign, data, ADDRESS, OpenPGPKey)
149
150     @inlineCallbacks
151     def test_verify_with_wrong_key_raises(self):
152         data = 'data'
153         pgp = openpgp.OpenPGPScheme(
154             self._soledad, gpgbinary=self.gpg_binary_path)
155         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
156         privkey = yield pgp.get_key(ADDRESS, private=True)
157         signed = pgp.sign(data, privkey)
158         yield pgp.put_ascii_key(PUBLIC_KEY_2, ADDRESS_2)
159         wrongkey = yield pgp.get_key(ADDRESS_2)
160         self.assertFalse(pgp.verify(signed, wrongkey))
161
162     @inlineCallbacks
163     def test_encrypt_sign_with_public_raises(self):
164         data = 'data'
165         pgp = openpgp.OpenPGPScheme(
166             self._soledad, gpgbinary=self.gpg_binary_path)
167         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
168         privkey = yield pgp.get_key(ADDRESS, private=True)
169         pubkey = yield pgp.get_key(ADDRESS, private=False)
170         self.assertRaises(
171             AssertionError,
172             pgp.encrypt, data, privkey, sign=pubkey)
173
174     @inlineCallbacks
175     def test_decrypt_verify_with_private_raises(self):
176         data = 'data'
177         pgp = openpgp.OpenPGPScheme(
178             self._soledad, gpgbinary=self.gpg_binary_path)
179         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
180         privkey = yield pgp.get_key(ADDRESS, private=True)
181         pubkey = yield pgp.get_key(ADDRESS, private=False)
182         encrypted_and_signed = pgp.encrypt(
183             data, pubkey, sign=privkey)
184         self.assertRaises(
185             AssertionError,
186             pgp.decrypt,
187             encrypted_and_signed, privkey, verify=privkey)
188
189     @inlineCallbacks
190     def test_decrypt_verify_with_wrong_key(self):
191         data = 'data'
192         pgp = openpgp.OpenPGPScheme(
193             self._soledad, gpgbinary=self.gpg_binary_path)
194         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
195         privkey = yield pgp.get_key(ADDRESS, private=True)
196         pubkey = yield pgp.get_key(ADDRESS, private=False)
197         encrypted_and_signed = pgp.encrypt(data, pubkey, sign=privkey)
198         yield pgp.put_ascii_key(PUBLIC_KEY_2, ADDRESS_2)
199         wrongkey = yield pgp.get_key(ADDRESS_2)
200         decrypted, validsign = pgp.decrypt(encrypted_and_signed, privkey,
201                                            verify=wrongkey)
202         self.assertEqual(decrypted, data)
203         self.assertFalse(validsign)
204
205     @inlineCallbacks
206     def test_sign_verify(self):
207         data = 'data'
208         pgp = openpgp.OpenPGPScheme(
209             self._soledad, gpgbinary=self.gpg_binary_path)
210         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
211         privkey = yield pgp.get_key(ADDRESS, private=True)
212         signed = pgp.sign(data, privkey, detach=False)
213         pubkey = yield pgp.get_key(ADDRESS, private=False)
214         validsign = pgp.verify(signed, pubkey)
215         self.assertTrue(validsign)
216
217     @inlineCallbacks
218     def test_encrypt_sign_decrypt_verify(self):
219         pgp = openpgp.OpenPGPScheme(
220             self._soledad, gpgbinary=self.gpg_binary_path)
221
222         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
223         pubkey = yield pgp.get_key(ADDRESS, private=False)
224         privkey = yield pgp.get_key(ADDRESS, private=True)
225
226         yield pgp.put_ascii_key(PRIVATE_KEY_2, ADDRESS_2)
227         pubkey2 = yield pgp.get_key(ADDRESS_2, private=False)
228         privkey2 = yield pgp.get_key(ADDRESS_2, private=True)
229
230         data = 'data'
231         encrypted_and_signed = pgp.encrypt(
232             data, pubkey2, sign=privkey)
233         res, validsign = pgp.decrypt(
234             encrypted_and_signed, privkey2, verify=pubkey)
235         self.assertEqual(data, res)
236         self.assertTrue(validsign)
237
238     @inlineCallbacks
239     def test_sign_verify_detached_sig(self):
240         data = 'data'
241         pgp = openpgp.OpenPGPScheme(
242             self._soledad, gpgbinary=self.gpg_binary_path)
243         yield pgp.put_ascii_key(PRIVATE_KEY, ADDRESS)
244         privkey = yield pgp.get_key(ADDRESS, private=True)
245         signature = yield pgp.sign(data, privkey, detach=True)
246         pubkey = yield pgp.get_key(ADDRESS, private=False)
247         validsign = pgp.verify(data, pubkey, detached_sig=signature)
248         self.assertTrue(validsign)
249
250     def _assert_key_not_found(self, pgp, address, private=False):
251         d = pgp.get_key(address, private=private)
252         return self.assertFailure(d, KeyNotFound)