/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 breezy/gpg.py

  • Committer: Jelmer Vernooij
  • Date: 2018-03-24 17:48:04 UTC
  • mfrom: (6921 work)
  • mto: This revision was merged to the branch mainline in revision 6923.
  • Revision ID: jelmer@jelmer.uk-20180324174804-xf22o05byoj12x1q
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
52
52
SIGNATURE_NOT_SIGNED = 3
53
53
SIGNATURE_EXPIRED = 4
54
54
 
 
55
MODE_NORMAL = 0
 
56
MODE_DETACH = 1
 
57
MODE_CLEAR = 2
 
58
 
55
59
 
56
60
class GpgNotInstalled(errors.DependencyNotPresent):
57
61
 
99
103
    result = []
100
104
    all_verifiable = True
101
105
    total = len(revids)
102
 
    pb = ui.ui_factory.nested_progress_bar()
103
 
    try:
 
106
    with ui.ui_factory.nested_progress_bar() as pb:
104
107
        for i, (rev_id, verification_result, uid) in enumerate(
105
108
                repository.verify_revision_signatures(
106
109
                    revids, strategy)):
111
114
                all_verifiable = False
112
115
            if process_events_callback is not None:
113
116
                process_events_callback()
114
 
    finally:
115
 
        pb.finished()
116
117
    return (count, result, all_verifiable)
117
118
 
118
119
 
126
127
    def __init__(self, ignored):
127
128
        """Real strategies take a configuration."""
128
129
 
129
 
    def sign(self, content):
 
130
    def sign(self, content, mode):
130
131
        raise SigningFailed('Signing is disabled.')
131
132
 
132
 
    def verify(self, content, testament):
 
133
    def verify(self, signed_data, signature=None):
133
134
        raise SignatureVerificationFailed('Signature verification is \
134
135
disabled.')
135
136
 
149
150
    def __init__(self, ignored):
150
151
        """Real strategies take a configuration."""
151
152
 
152
 
    def sign(self, content):
 
153
    def sign(self, content, mode):
153
154
        return ("-----BEGIN PSEUDO-SIGNED CONTENT-----\n" + content +
154
155
                "-----END PSEUDO-SIGNED CONTENT-----\n")
155
156
 
156
 
    def verify(self, content, testament):
157
 
        return SIGNATURE_VALID, None
 
157
    def verify(self, signed_data, signature=None):
 
158
        plain_text = signed_data.replace("-----BEGIN PSEUDO-SIGNED CONTENT-----\n", "")
 
159
        plain_text = plain_text.replace("-----END PSEUDO-SIGNED CONTENT-----\n", "")
 
160
        return SIGNATURE_VALID, None, plain_text
158
161
 
159
162
    def set_acceptable_keys(self, command_line_input):
160
163
        if command_line_input is not None:
190
193
        try:
191
194
            import gpg
192
195
            self.context = gpg.Context()
 
196
            self.context.armor = True
 
197
            self.context.signers = self._get_signing_keys()
193
198
        except ImportError as error:
194
199
            pass # can't use verify()
195
200
 
196
 
        self.context.signers = self._get_signing_keys()
197
 
 
198
201
    def _get_signing_keys(self):
199
202
        import gpg
200
203
        keyname = self._config_stack.get('gpg_signing_key')
227
230
        except ImportError as error:
228
231
            return False
229
232
 
230
 
    def sign(self, content):
 
233
    def sign(self, content, mode):
231
234
        import gpg
232
235
        if isinstance(content, unicode):
233
236
            raise errors.BzrBadParameterUnicode('content')
235
238
        plain_text = gpg.Data(content)
236
239
        try:
237
240
            output, result = self.context.sign(
238
 
                plain_text, mode=gpg.constants.sig.mode.CLEAR)
 
241
                plain_text, mode={
 
242
                    MODE_DETACH: gpg.constants.sig.mode.DETACH,
 
243
                    MODE_CLEAR: gpg.constants.sig.mode.CLEAR,
 
244
                    MODE_NORMAL: gpg.constants.sig.mode.NORMAL,
 
245
                    }[mode])
239
246
        except gpg.errors.GPGMEError as error:
240
247
            raise SigningFailed(str(error))
241
248
 
242
249
        return output
243
250
 
244
 
    def verify(self, content, testament):
 
251
    def verify(self, signed_data, signature=None):
245
252
        """Check content has a valid signature.
246
253
 
247
 
        :param content: the commit signature
248
 
        :param testament: the valid testament string for the commit
 
254
        :param signed_data; Signed data
 
255
        :param signature: optional signature (if detached)
249
256
 
250
 
        :return: SIGNATURE_VALID or a failed SIGNATURE_ value, key uid if valid
 
257
        :return: SIGNATURE_VALID or a failed SIGNATURE_ value, key uid if valid, plain text
251
258
        """
252
259
        try:
253
260
            import gpg
254
261
        except ImportError as error:
255
262
            raise errors.GpgNotInstalled(error)
256
263
 
257
 
        signature = gpg.Data(content)
258
 
        sink = gpg.Data()
 
264
        signed_data = gpg.Data(signed_data)
 
265
        if signature:
 
266
            signature = gpg.Data(signature)
259
267
        try:
260
 
            plain_output, result = self.context.verify(signature)
 
268
            plain_output, result = self.context.verify(signed_data, signature)
261
269
        except gpg.errors.BadSignatures as error:
262
270
            fingerprint = error.result.signatures[0].fpr
263
271
            if error.result.signatures[0].summary & gpg.constants.SIGSUM_KEY_EXPIRED:
265
273
                if expires > error.result.signatures[0].timestamp:
266
274
                    # The expired key was not expired at time of signing.
267
275
                    # test_verify_expired_but_valid()
268
 
                    return SIGNATURE_EXPIRED, fingerprint[-8:]
 
276
                    return SIGNATURE_EXPIRED, fingerprint[-8:], None
269
277
                else:
270
278
                    # I can't work out how to create a test where the signature
271
279
                    # was expired at the time of signing.
272
 
                    return SIGNATURE_NOT_VALID, None
 
280
                    return SIGNATURE_NOT_VALID, None, None
273
281
 
274
282
            # GPG does not know this key.
275
283
            # test_verify_unknown_key()
276
284
            if error.result.signatures[0].summary & gpg.constants.SIGSUM_KEY_MISSING:
277
 
                return SIGNATURE_KEY_MISSING, fingerprint[-8:]
 
285
                return SIGNATURE_KEY_MISSING, fingerprint[-8:], None
278
286
 
279
 
            return SIGNATURE_NOT_VALID, None
 
287
            return SIGNATURE_NOT_VALID, None, None
280
288
        except gpg.errors.GPGMEError as error:
281
 
            raise SignatureVerificationFailed(error[2])
 
289
            raise SignatureVerificationFailed(error)
282
290
 
283
291
        # No result if input is invalid.
284
292
        # test_verify_invalid()
285
293
        if len(result.signatures) == 0:
286
 
            return SIGNATURE_NOT_VALID, None
 
294
            return SIGNATURE_NOT_VALID, None, plain_output
 
295
 
287
296
        # User has specified a list of acceptable keys, check our result is in
288
297
        # it.  test_verify_unacceptable_key()
289
298
        fingerprint = result.signatures[0].fpr
290
299
        if self.acceptable_keys is not None:
291
300
            if not fingerprint in self.acceptable_keys:
292
 
                return SIGNATURE_KEY_MISSING, fingerprint[-8:]
293
 
        # Check the signature actually matches the testament.
294
 
        # test_verify_bad_testament()
295
 
        if testament != plain_output:
296
 
            return SIGNATURE_NOT_VALID, None
 
301
                return SIGNATURE_KEY_MISSING, fingerprint[-8:], plain_output
297
302
        # Yay gpg set the valid bit.
298
303
        # Can't write a test for this one as you can't set a key to be
299
304
        # trusted using gpg.
301
306
            key = self.context.get_key(fingerprint)
302
307
            name = key.uids[0].name
303
308
            email = key.uids[0].email
304
 
            return SIGNATURE_VALID, name + " <" + email + ">"
 
309
            return SIGNATURE_VALID, name.decode('utf-8') + u" <" + email.decode('utf-8') + u">", plain_output
305
310
        # Sigsum_red indicates a problem, unfortunatly I have not been able
306
311
        # to write any tests which actually set this.
307
312
        if result.signatures[0].summary & gpg.constants.SIGSUM_RED:
308
 
            return SIGNATURE_NOT_VALID, None
 
313
            return SIGNATURE_NOT_VALID, None, plain_output
309
314
        # Summary isn't set if sig is valid but key is untrusted but if user
310
315
        # has explicity set the key as acceptable we can validate it.
311
316
        if result.signatures[0].summary == 0 and self.acceptable_keys is not None:
312
317
            if fingerprint in self.acceptable_keys:
313
318
                # test_verify_untrusted_but_accepted()
314
 
                return SIGNATURE_VALID, None
 
319
                return SIGNATURE_VALID, None, plain_output
315
320
        # test_verify_valid_but_untrusted()
316
321
        if result.signatures[0].summary == 0 and self.acceptable_keys is None:
317
 
            return SIGNATURE_NOT_VALID, None
 
322
            return SIGNATURE_NOT_VALID, None, plain_output
318
323
        # Other error types such as revoked keys should (I think) be caught by
319
324
        # SIGSUM_RED so anything else means something is buggy.
320
325
        raise SignatureVerificationFailed(