/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/gpg.py

  • Committer: Jonathan Riddell
  • Date: 2011-06-22 13:53:20 UTC
  • mto: This revision was merged to the branch mainline in revision 6003.
  • Revision ID: jriddell@canonical.com-20110622135320-ct7e52dz851m1ird
more tests for new config options

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
 
1
# Copyright (C) 2005, 2011 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
19
19
 
20
20
import os
21
21
import sys
 
22
from StringIO import StringIO
22
23
 
23
24
from bzrlib.lazy_import import lazy_import
24
25
lazy_import(globals(), """
29
30
    errors,
30
31
    trace,
31
32
    ui,
 
33
    i18n,
32
34
    )
33
35
""")
34
36
 
 
37
#verification results
 
38
SIGNATURE_VALID = 0
 
39
SIGNATURE_KEY_MISSING = 1
 
40
SIGNATURE_NOT_VALID = 2
 
41
SIGNATURE_NOT_SIGNED = 3
 
42
 
35
43
 
36
44
class DisabledGPGStrategy(object):
37
45
    """A GPG Strategy that makes everything fail."""
42
50
    def sign(self, content):
43
51
        raise errors.SigningFailed('Signing is disabled.')
44
52
 
 
53
    def verify(self, content, testament):
 
54
        raise errors.SignatureVerificationFailed('Signature verification is \
 
55
disabled.')
 
56
 
 
57
    def set_acceptable_keys(self, key_patterns):
 
58
        pass
 
59
 
45
60
 
46
61
class LoopbackGPGStrategy(object):
47
62
    """A GPG Strategy that acts like 'cat' - data is just passed through."""
53
68
        return ("-----BEGIN PSEUDO-SIGNED CONTENT-----\n" + content +
54
69
                "-----END PSEUDO-SIGNED CONTENT-----\n")
55
70
 
 
71
    def verify(self, content, testament):
 
72
        return SIGNATURE_VALID, None
 
73
 
 
74
    def set_acceptable_keys(self, key_patterns):
 
75
        patterns = key_patterns.split(",")
 
76
        self.acceptable_keys = []
 
77
        for pattern in patterns:
 
78
            if pattern == "unknown":
 
79
                pass
 
80
            else:
 
81
                self.acceptable_keys.append(pattern)
 
82
 
56
83
 
57
84
def _set_gpg_tty():
58
85
    tty = os.environ.get('TTY')
70
97
class GPGStrategy(object):
71
98
    """GPG Signing and checking facilities."""
72
99
 
 
100
    acceptable_keys = None
 
101
 
73
102
    def _command_line(self):
74
103
        return [self._config.gpg_signing_command(), '--clearsign']
75
104
 
111
140
                raise errors.SigningFailed(self._command_line())
112
141
            else:
113
142
                raise
 
143
 
 
144
    def verify(self, content, testament):
 
145
        """Check content has a valid signature.
 
146
        
 
147
        :param content: the commit signature
 
148
        :param testament: the valid testament string for the commit
 
149
        
 
150
        :return: SIGNATURE_VALID or a failed SIGNATURE_ value, key uid if valid
 
151
        """
 
152
        try:
 
153
            import gpgme
 
154
        except ImportError, error:
 
155
            raise errors.GpgmeNotInstalled(error)
 
156
 
 
157
        context = gpgme.Context()
 
158
        signature = StringIO(content)
 
159
        plain_output = StringIO()
 
160
        
 
161
        try:
 
162
            result = context.verify(signature, None, plain_output)
 
163
        except gpgme.GpgmeError,error:
 
164
            raise errors.SignatureVerificationFailed(error[2])
 
165
 
 
166
        if len(result) == 0:
 
167
            return SIGNATURE_NOT_VALID, None
 
168
        fingerprint = result[0].fpr
 
169
        if self.acceptable_keys is not None:
 
170
            if not fingerprint in self.acceptable_keys:
 
171
                return SIGNATURE_KEY_MISSING, fingerprint[-8:]
 
172
        if testament != plain_output.getvalue():
 
173
            return SIGNATURE_NOT_VALID, None
 
174
        if result[0].summary & gpgme.SIGSUM_VALID:
 
175
            key = context.get_key(fingerprint)
 
176
            name = key.uids[0].name
 
177
            email = key.uids[0].email
 
178
            return SIGNATURE_VALID, name + " <" + email + ">"
 
179
        if result[0].summary & gpgme.SIGSUM_RED:
 
180
            return SIGNATURE_NOT_VALID, None
 
181
        if result[0].summary & gpgme.SIGSUM_KEY_MISSING:
 
182
            return SIGNATURE_KEY_MISSING, fingerprint[-8:]
 
183
        #summary isn't set if sig is valid but key is untrusted
 
184
        if result[0].summary == 0 and self.acceptable_keys is not None:
 
185
            if fingerprint in self.acceptable_keys:
 
186
                return SIGNATURE_VALID, None
 
187
        else:
 
188
            return SIGNATURE_KEY_MISSING, None
 
189
        raise errors.SignatureVerificationFailed("Unknown GnuPG key "\
 
190
                                                 "verification result")
 
191
 
 
192
    def set_acceptable_keys(self, key_patterns):
 
193
        try:
 
194
            import gpgme
 
195
        except ImportError, error:
 
196
            raise errors.GpgmeNotInstalled(error)
 
197
        patterns = key_patterns.split(",")
 
198
 
 
199
        self.acceptable_keys = []
 
200
        context = gpgme.Context()
 
201
        for pattern in patterns:
 
202
            result = context.keylist(pattern)
 
203
            found_key = False
 
204
            for key in result:
 
205
                found_key = True
 
206
                self.acceptable_keys.append(key.subkeys[0].fpr)
 
207
                trace.mutter("Added acceptable key: " + key.subkeys[0].fpr)
 
208
            if not found_key:
 
209
                trace.note(i18n.gettext(
 
210
                           "No GnuPG key results for pattern: {}"
 
211
                            ).format(pattern))