126
127
def __init__(self, ignored):
127
128
"""Real strategies take a configuration."""
129
def sign(self, content):
130
def sign(self, content, mode):
130
131
raise SigningFailed('Signing is disabled.')
132
def verify(self, content, testament):
133
def verify(self, signed_data, signature=None):
133
134
raise SignatureVerificationFailed('Signature verification is \
149
150
def __init__(self, ignored):
150
151
"""Real strategies take a configuration."""
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")
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
159
162
def set_acceptable_keys(self, command_line_input):
160
163
if command_line_input is not None:
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()
196
self.context.signers = self._get_signing_keys()
198
201
def _get_signing_keys(self):
200
203
keyname = self._config_stack.get('gpg_signing_key')
235
238
plain_text = gpg.Data(content)
237
240
output, result = self.context.sign(
238
plain_text, mode=gpg.constants.sig.mode.CLEAR)
242
MODE_DETACH: gpg.constants.sig.mode.DETACH,
243
MODE_CLEAR: gpg.constants.sig.mode.CLEAR,
244
MODE_NORMAL: gpg.constants.sig.mode.NORMAL,
239
246
except gpg.errors.GPGMEError as error:
240
247
raise SigningFailed(str(error))
244
def verify(self, content, testament):
251
def verify(self, signed_data, signature=None):
245
252
"""Check content has a valid signature.
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)
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
254
261
except ImportError as error:
255
262
raise errors.GpgNotInstalled(error)
257
signature = gpg.Data(content)
264
signed_data = gpg.Data(signed_data)
266
signature = gpg.Data(signature)
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
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
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
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)
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
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(