~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_gpg.py

  • Committer: Tarmac
  • Author(s): Vincent Ladeuil
  • Date: 2017-01-30 14:42:05 UTC
  • mfrom: (6620.1.1 trunk)
  • Revision ID: tarmac-20170130144205-r8fh2xpmiuxyozpv
Merge  2.7 into trunk including fix for bug #1657238 [r=vila]

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
# import system imports here
21
21
import sys
22
22
 
23
 
from bzrlib import errors, ui
24
 
import bzrlib.gpg as gpg
25
 
from bzrlib.tests import TestCase
26
 
from bzrlib.tests import features
27
 
 
28
 
class FakeConfig(object):
29
 
 
30
 
    def gpg_signing_command(self):
31
 
        return "false"
32
 
 
33
 
    def acceptable_keys(self):
34
 
        return None
35
 
 
36
 
 
37
 
class TestCommandLine(TestCase):
 
23
from bzrlib import (
 
24
    config,
 
25
    errors,
 
26
    gpg,
 
27
    tests,
 
28
    trace,
 
29
    ui,
 
30
    )
 
31
from bzrlib.tests import (
 
32
    TestCase,
 
33
    features,
 
34
    )
 
35
 
 
36
 
 
37
class FakeConfig(config.MemoryStack):
 
38
 
 
39
    def __init__(self, content=None):
 
40
        if content is None:
 
41
            content = '''
 
42
gpg_signing_key=amy@example.com
 
43
gpg_signing_command=false'''
 
44
        super(FakeConfig, self).__init__(content)
 
45
 
 
46
 
 
47
class TestCommandLine(tests.TestCase):
 
48
 
 
49
    def setUp(self):
 
50
        super(TestCommandLine, self).setUp()
 
51
        self.my_gpg = gpg.GPGStrategy(FakeConfig())
38
52
 
39
53
    def test_signing_command_line(self):
40
 
        my_gpg = gpg.GPGStrategy(FakeConfig())
41
 
        self.assertEqual(['false',  '--clearsign'],
 
54
        self.assertEqual(['false',  '--clearsign', '-u', 'amy@example.com'],
 
55
                         self.my_gpg._command_line())
 
56
 
 
57
    def test_signing_command_line_from_default(self):
 
58
        # Using 'default' for gpg_signing_key will use the mail part of 'email'
 
59
        my_gpg = gpg.GPGStrategy(FakeConfig('''
 
60
email=Amy <amy@example.com>
 
61
gpg_signing_key=default
 
62
gpg_signing_command=false'''))
 
63
        self.assertEqual(['false',  '--clearsign', '-u', 'amy@example.com'],
 
64
                         my_gpg._command_line())
 
65
 
 
66
    def test_signing_command_line_from_email(self):
 
67
        # Not setting gpg_signing_key will use the mail part of 'email'
 
68
        my_gpg = gpg.GPGStrategy(FakeConfig('''
 
69
email=Amy <amy@example.com>
 
70
gpg_signing_command=false'''))
 
71
        self.assertEqual(['false',  '--clearsign', '-u', 'amy@example.com'],
42
72
                         my_gpg._command_line())
43
73
 
44
74
    def test_checks_return_code(self):
45
75
        # This test needs a unix like platform - one with 'false' to run.
46
76
        # if you have one, please make this work :)
47
 
        my_gpg = gpg.GPGStrategy(FakeConfig())
48
 
        self.assertRaises(errors.SigningFailed, my_gpg.sign, 'content')
 
77
        self.assertRaises(errors.SigningFailed, self.my_gpg.sign, 'content')
49
78
 
50
79
    def assertProduces(self, content):
51
80
        # This needs a 'cat' command or similar to work.
52
 
        my_gpg = gpg.GPGStrategy(FakeConfig())
53
81
        if sys.platform == 'win32':
54
82
            # Windows doesn't come with cat, and we don't require it
55
83
            # so lets try using python instead.
56
84
            # But stupid windows and line-ending conversions.
57
85
            # It is too much work to make sys.stdout be in binary mode.
58
86
            # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65443
59
 
            my_gpg._command_line = lambda:[sys.executable, '-c',
 
87
            self.my_gpg._command_line = lambda:[sys.executable, '-c',
60
88
                    'import sys; sys.stdout.write(sys.stdin.read())']
61
89
            new_content = content.replace('\n', '\r\n')
62
90
 
63
 
            self.assertEqual(new_content, my_gpg.sign(content))
 
91
            self.assertEqual(new_content, self.my_gpg.sign(content))
64
92
        else:
65
 
            my_gpg._command_line = lambda:['cat', '-']
66
 
            self.assertEqual(content, my_gpg.sign(content))
 
93
            self.my_gpg._command_line = lambda:['cat', '-']
 
94
            self.assertEqual(content, self.my_gpg.sign(content))
67
95
 
68
96
    def test_returns_output(self):
69
97
        content = "some content\nwith newlines\n"
88
116
        self.assertRaises(errors.BzrBadParameterUnicode,
89
117
                          self.assertProduces, u'foo')
90
118
 
 
119
 
 
120
class TestVerify(TestCase):
 
121
 
91
122
    def import_keys(self):
92
123
        from StringIO import StringIO
93
124
        import gpgme
184
215
-----END PGP PRIVATE KEY BLOCK-----
185
216
""")
186
217
 
 
218
        revoked_key = StringIO("""-----BEGIN PGP PUBLIC KEY BLOCK-----
 
219
Version: GnuPG v1.4.11 (GNU/Linux)
 
220
 
 
221
mI0ETjlW5gEEAOb/6P+TVM59E897wRtatxys2BhsHCXM4T7xjIiANfDwejDdifqh
 
222
tluTfSJLLxPembtrrEjux1C0AJgc+f0MIfsc3Pr3eFJzKB2ot/1IVG1/1KnA0zt3
 
223
W2xPT3lRib27WJ9Fag+dMtQaIzgJ7/n2DFxsFZ33FD2kxrEXB2exGg6FABEBAAGI
 
224
pgQgAQIAEAUCTjlXkAkdAHJldm9rZWQACgkQjs6dvEpb0cQPHAP/Wi9rbx0e+1Sf
 
225
ziGgyVdr3m3A6uvze5oXKVgFRbGRUYSH4/I8GW0W9x4TcRg9h+YaQ8NUdADr9kNE
 
226
tKAljLqYA5qdqSfYuaij1M++Xj+KUZ359R74sHuQqwnRy1XXQNfRs/QpXA7vLdds
 
227
rjg+pbWuXO92TZJUdnqtWW+VEyZBsPy0G3Rlc3Qga2V5IDx0ZXN0QGV4YW1wbGUu
 
228
Y29tPoi4BBMBAgAiBQJOOVbmAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAK
 
229
CRCOzp28SlvRxNWzA/42WVmI0b+6mF/imEOlY1TiyvrcpK250rkSDsCtL4lOwy7G
 
230
antZhpgNfnXRd/ySfsS3EB6dpOWgOSxGRvWQhA+vxBT9BYNk49qd3JIrSaSWpR12
 
231
rET8qO1rEQQFWsw03CxTGujxGlmEO+a1yguRXp2UWaY7FngcQmD+8q7BUIVm7riN
 
232
BE45VuYBBADTEH2jHTjNCc5CMOhea6EJTrkx3upcEqB2oyhWeSWJiBGOxlcddsjo
 
233
3J3/EmBB8kK1hM9TidD3SG64x1N287lg8ELJBlKv+pQVyxohGJ1u/THgpTDMMQcL
 
234
luG5rAHQGSfyzKTiOnaTyBYg3M/nzgUOU9dKEFB0EA3tjUXFOT+r3wARAQABiJ8E
 
235
GAECAAkFAk45VuYCGwwACgkQjs6dvEpb0cRSLQP/fzCWX2lXwlwWiVF8BOPF7o9z
 
236
icHErc7/X17RGb4qj1kVf+UkRdUWJrbEVh4h6MncBIuA70WsYogiw+Kz/0LCtQAR
 
237
YUJsPy/EL++OKPH1aFasOdTxwkTka85+RdYqhP1+z/aYLFMWq6mRFI+o6x2k5mGi
 
238
7dMv2kKTJPoXUpiXJbg=
 
239
=hLYO
 
240
-----END PGP PUBLIC KEY BLOCK-----
 
241
""")
 
242
 
 
243
        expired_key = StringIO("""-----BEGIN PGP PUBLIC KEY BLOCK-----
 
244
Version: GnuPG v1.4.11 (GNU/Linux)
 
245
 
 
246
mI0ETjZ6PAEEALkR4GcFQidCCxV7pgQwQd5MZua0YO2l92fVqHX+PhnZ6egCLKdD
 
247
2bWlMUd6MLPF3FlRL7BBAxvW/DazkBOp7ljsnpMpptEzY49Uem1irYLYiVb9zK96
 
248
0sQZzFxFkfEYetQEXC68mIck8tbySOX5NAOw++3jFm3J7dsU1R3XtYzRABEBAAG0
 
249
G3Rlc3Qga2V5IDx0ZXN0QGV4YW1wbGUuY29tPoi+BBMBAgAoBQJONno8AhsDBQkA
 
250
AVGABgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAc4m97T40VEz+DA/9PBphG
 
251
Yp9cHVaHSfTUKGTGgIbvRe60sFNpDCYZeAGDrygOMuI8MNzbVpwefRBFHVPx7jWd
 
252
rrYMsLkcsNUS9D0baU+0D/qp7JVg7ZSQtG0O6IG4eTZhibteY1fu0+unlXmg9NHx
 
253
5VvhwzBiJDYji00M2p/CZEMiYFUuy76CsxUpN7iNBE42ejwBBACkv2/mX7IPQg0C
 
254
A3KSrJsJv+sdvKm4b4xuI4OwagwTIVz4KlTqV4IBrVjSBfwyMXucXz0bTW85qjgA
 
255
+n67td8vyjYYZUEz1uY9lSquQQDnAN0txL3cLHZXWiWOkmzZVddQtlflK2a/J9o0
 
256
QkHPVUm+hc4l64dIzStrNl2S66fAvQARAQABiKUEGAECAA8FAk42ejwCGwwFCQAB
 
257
UYAACgkQHOJve0+NFROEYQP/epg+o8iBs31hkSERyZjrRR66LpywezWj30Rn/3mX
 
258
Fzi9HkF4xLemWOzdNt9C5PYrOep85PQg8haEjknxVjZFS0ikT1h3OWk/TF1ZrLVm
 
259
WzyX8DaHQEjKpLJJjXcAbTiZBNMk0QaVC9RvIeHpCf3n3DC49DdjsPJRMKOn8KDi
 
260
kRk=
 
261
=p0gt
 
262
-----END PGP PUBLIC KEY BLOCK-----
 
263
""")
187
264
        context.import_(key)
188
265
        context.import_(secret_key)
 
266
        context.import_(revoked_key)
 
267
        context.import_(expired_key)
189
268
 
190
 
    def test_verify_valid(self):
 
269
    def test_verify_untrusted_but_accepted(self):
 
270
        #untrusted by gpg but listed as acceptable_keys by user
191
271
        self.requireFeature(features.gpgme)
192
272
        self.import_keys()
193
 
            
 
273
 
194
274
        content = """-----BEGIN PGP SIGNED MESSAGE-----
195
275
Hash: SHA1
196
276
 
218
298
        self.assertEqual((gpg.SIGNATURE_VALID, None), my_gpg.verify(content,
219
299
                            plain))
220
300
 
 
301
    def test_verify_unacceptable_key(self):
 
302
        self.requireFeature(features.gpgme)
 
303
        self.import_keys()
 
304
 
 
305
        content = """-----BEGIN PGP SIGNED MESSAGE-----
 
306
Hash: SHA1
 
307
 
 
308
bazaar-ng testament short form 1
 
309
revision-id: amy@example.com-20110527185938-hluafawphszb8dl1
 
310
sha1: 6411f9bdf6571200357140c9ce7c0f50106ac9a4
 
311
-----BEGIN PGP SIGNATURE-----
 
312
Version: GnuPG v1.4.11 (GNU/Linux)
 
313
 
 
314
iQEcBAEBAgAGBQJN+ekFAAoJEIdoGx7jCA5FGtEH/i+XxJRvqU6wdBtLVrGBMAGk
 
315
FZ5VP+KyXYtymSbgSstj/vM12NeMIeFs3xGnNnYuX1MIcY6We5TKtCH0epY6ym5+
 
316
6g2Q2QpQ5/sT2d0mWzR0K4uVngmxVQaXTdk5PdZ40O7ULeDLW6CxzxMHyUL1rsIx
 
317
7UBUTBh1O/1n3ZfD99hUkm3hVcnsN90uTKH59zV9NWwArU0cug60+5eDKJhSJDbG
 
318
rIwlqbFAjDZ7L/48e+IaYIJwBZFzMBpJKdCxzALLtauMf+KK8hGiL2hrRbWm7ty6
 
319
NgxfkMYOB4rDPdSstT35N+5uBG3n/UzjxHssi0svMfVETYYX40y57dm2eZQXFp8=
 
320
=iwsn
 
321
-----END PGP SIGNATURE-----
 
322
"""
 
323
        plain = """bazaar-ng testament short form 1
 
324
revision-id: amy@example.com-20110527185938-hluafawphszb8dl1
 
325
sha1: 6411f9bdf6571200357140c9ce7c0f50106ac9a4
 
326
"""
 
327
        my_gpg = gpg.GPGStrategy(FakeConfig())
 
328
        my_gpg.set_acceptable_keys("foo@example.com")
 
329
        self.assertEqual((gpg.SIGNATURE_KEY_MISSING, u'E3080E45'),
 
330
                         my_gpg.verify(content, plain))
 
331
 
 
332
    def test_verify_valid_but_untrusted(self):
 
333
        self.requireFeature(features.gpgme)
 
334
        self.import_keys()
 
335
 
 
336
        content = """-----BEGIN PGP SIGNED MESSAGE-----
 
337
Hash: SHA1
 
338
 
 
339
bazaar-ng testament short form 1
 
340
revision-id: amy@example.com-20110527185938-hluafawphszb8dl1
 
341
sha1: 6411f9bdf6571200357140c9ce7c0f50106ac9a4
 
342
-----BEGIN PGP SIGNATURE-----
 
343
Version: GnuPG v1.4.11 (GNU/Linux)
 
344
 
 
345
iQEcBAEBAgAGBQJN+ekFAAoJEIdoGx7jCA5FGtEH/i+XxJRvqU6wdBtLVrGBMAGk
 
346
FZ5VP+KyXYtymSbgSstj/vM12NeMIeFs3xGnNnYuX1MIcY6We5TKtCH0epY6ym5+
 
347
6g2Q2QpQ5/sT2d0mWzR0K4uVngmxVQaXTdk5PdZ40O7ULeDLW6CxzxMHyUL1rsIx
 
348
7UBUTBh1O/1n3ZfD99hUkm3hVcnsN90uTKH59zV9NWwArU0cug60+5eDKJhSJDbG
 
349
rIwlqbFAjDZ7L/48e+IaYIJwBZFzMBpJKdCxzALLtauMf+KK8hGiL2hrRbWm7ty6
 
350
NgxfkMYOB4rDPdSstT35N+5uBG3n/UzjxHssi0svMfVETYYX40y57dm2eZQXFp8=
 
351
=iwsn
 
352
-----END PGP SIGNATURE-----
 
353
"""
 
354
        plain = """bazaar-ng testament short form 1
 
355
revision-id: amy@example.com-20110527185938-hluafawphszb8dl1
 
356
sha1: 6411f9bdf6571200357140c9ce7c0f50106ac9a4
 
357
"""
 
358
        my_gpg = gpg.GPGStrategy(FakeConfig())
 
359
        self.assertEqual((gpg.SIGNATURE_NOT_VALID, None), my_gpg.verify(content,
 
360
                            plain))
 
361
 
221
362
    def test_verify_bad_testament(self):
222
363
        self.requireFeature(features.gpgme)
223
364
        self.import_keys()
224
 
            
 
365
 
225
366
        content = """-----BEGIN PGP SIGNED MESSAGE-----
226
367
Hash: SHA1
227
368
 
249
390
        self.assertEqual((gpg.SIGNATURE_NOT_VALID, None), my_gpg.verify(content,
250
391
                            plain))
251
392
 
 
393
 
 
394
    def test_verify_revoked_signature(self):
 
395
        self.requireFeature(features.gpgme)
 
396
        self.import_keys()
 
397
 
 
398
        content = """-----BEGIN PGP SIGNED MESSAGE-----
 
399
Hash: SHA1
 
400
 
 
401
asdf
 
402
-----BEGIN PGP SIGNATURE-----
 
403
Version: GnuPG v1.4.11 (GNU/Linux)
 
404
 
 
405
iJwEAQECAAYFAk45V18ACgkQjs6dvEpb0cSIZQP/eOGTXGPlrNwvDkcX2d8O///I
 
406
ecB4sUIUEpv1XAk1MkNu58lsjjK72lRaLusEGqd7HwrFmpxVeVs0oWLg23PNPCFs
 
407
yJBID9ma+VxFVPtkEFnrc1R72sBJLfBcTxMkwVTC8eeznjdtn+cg+aLkxbPdrGnr
 
408
JFA6kUIJU2w9LU/b88Y=
 
409
=UuRX
 
410
-----END PGP SIGNATURE-----
 
411
"""
 
412
        plain = """asdf\n"""
 
413
        my_gpg = gpg.GPGStrategy(FakeConfig())
 
414
        my_gpg.set_acceptable_keys("test@example.com")
 
415
        self.assertEqual((gpg.SIGNATURE_NOT_VALID, None), my_gpg.verify(content,
 
416
                            plain))
 
417
 
252
418
    def test_verify_invalid(self):
253
419
        self.requireFeature(features.gpgme)
 
420
        self.import_keys()
254
421
        content = """-----BEGIN PGP SIGNED MESSAGE-----
255
422
Hash: SHA1
256
423
 
273
440
        self.assertEqual((gpg.SIGNATURE_NOT_VALID, None),
274
441
                            my_gpg.verify(content, plain))
275
442
 
 
443
    def test_verify_expired_but_valid(self):
 
444
        self.requireFeature(features.gpgme)
 
445
        self.import_keys()
 
446
        content = """-----BEGIN PGP SIGNED MESSAGE-----
 
447
Hash: SHA1
 
448
 
 
449
bazaar-ng testament short form 1
 
450
revision-id: test@example.com-20110801100657-f1dr1nompeex723z
 
451
sha1: 59ab434be4c2d5d646dee84f514aa09e1b72feeb
 
452
-----BEGIN PGP SIGNATURE-----
 
453
Version: GnuPG v1.4.10 (GNU/Linux)
 
454
 
 
455
iJwEAQECAAYFAk42esUACgkQHOJve0+NFRPc5wP7BoZkzBU8JaHMLv/LmqLr0sUz
 
456
zuE51ofZZ19L7KVtQWsOi4jFy0fi4A5TFwO8u9SOfoREGvkw292Uty9subSouK5/
 
457
mFmDOYPQ+O83zWgYZsBmMJWYDZ+X9I6XXZSbPtV/7XyTjaxtl5uRnDVJjg+AzKvD
 
458
dTp8VatVVrwuvzOPDVc=
 
459
=uHen
 
460
-----END PGP SIGNATURE-----
 
461
"""
 
462
        plain = """bazaar-ng testament short form 1
 
463
revision-id: test@example.com-20110801100657-f1dr1nompeex723z
 
464
sha1: 59ab434be4c2d5d646dee84f514aa09e1b72feeb
 
465
"""
 
466
        my_gpg = gpg.GPGStrategy(FakeConfig())
 
467
        self.assertEqual((gpg.SIGNATURE_EXPIRED, u'4F8D1513'),
 
468
                            my_gpg.verify(content, plain))
 
469
 
 
470
    def test_verify_unknown_key(self):
 
471
        self.requireFeature(features.gpgme)
 
472
        self.import_keys()
 
473
        content = """-----BEGIN PGP SIGNED MESSAGE-----
 
474
Hash: SHA1
 
475
 
 
476
asdf
 
477
-----BEGIN PGP SIGNATURE-----
 
478
Version: GnuPG v1.4.11 (GNU/Linux)
 
479
 
 
480
iQEcBAEBAgAGBQJOORKwAAoJENf6AkFdUeVvJDYH/1Cz+AJn1Jvy5n64o+0fZ5Ow
 
481
Y7UQb4QQTIOV7jI7n4hv/yBzuHrtImFzYvQl/o2Ezzi8B8L5gZtQy+xCUF+Q8iWs
 
482
gytZ5JUtSze7hDZo1NUl4etjoRGYqRfrUcvE2LkVH2dFbDGyyQfVmoeSHa5akuuP
 
483
QZmyg2F983rACVIpGvsqTH6RcBdvE9vx68lugeKQA8ArDn39/74FBFipFzrXSPij
 
484
eKFpl+yZmIb3g6HkPIC8o4j/tMvc37xF1OG5sBu8FT0+FC+VgY7vAblneDftAbyP
 
485
sIODx4WcfJtjLG/qkRYqJ4gDHo0eMpTJSk2CWebajdm4b+JBrM1F9mgKuZFLruE=
 
486
=RNR5
 
487
-----END PGP SIGNATURE-----
 
488
"""
 
489
        plain = "asdf\n"
 
490
        my_gpg = gpg.GPGStrategy(FakeConfig())
 
491
        self.assertEqual((gpg.SIGNATURE_KEY_MISSING, u'5D51E56F'),
 
492
                            my_gpg.verify(content, plain))
 
493
 
276
494
    def test_set_acceptable_keys(self):
277
495
        self.requireFeature(features.gpgme)
278
496
        self.import_keys()
281
499
        self.assertEqual(my_gpg.acceptable_keys,
282
500
                         [u'B5DEED5FCB15DAE6ECEF919587681B1EE3080E45'])
283
501
 
 
502
    def test_set_acceptable_keys_from_config(self):
 
503
        self.requireFeature(features.gpgme)
 
504
        self.import_keys()
 
505
        my_gpg = gpg.GPGStrategy(FakeConfig(
 
506
                'acceptable_keys=bazaar@example.com'))
 
507
        my_gpg.set_acceptable_keys(None)
 
508
        self.assertEqual(my_gpg.acceptable_keys,
 
509
                         [u'B5DEED5FCB15DAE6ECEF919587681B1EE3080E45'])
 
510
 
284
511
    def test_set_acceptable_keys_unknown(self):
285
512
        self.requireFeature(features.gpgme)
286
513
        my_gpg = gpg.GPGStrategy(FakeConfig())
 
514
        self.notes = []
 
515
        def note(*args):
 
516
            self.notes.append(args[0] % args[1:])
 
517
        self.overrideAttr(trace, 'note', note)
287
518
        my_gpg.set_acceptable_keys("unknown")
288
519
        self.assertEqual(my_gpg.acceptable_keys, [])
 
520
        self.assertEqual(self.notes,
 
521
            ['No GnuPG key results for pattern: unknown'])
289
522
 
290
523
 
291
524
class TestDisabled(TestCase):