python: stop raising BadSignatures from decrypt(verify=True)

* src/core.py (decrypt): filter out signatures with errors from the
returned verify_result, but avoid raising BadSignatures
* tests/t-decrypt-verify.py: ensure that only a single signature is
returned when evaluating cipher-3.asc, since the other signature is
unknown.

--

This change preserves the invariant that decrypt() only ever returns
valid signatures in the verify_result, but it avoids unnecessary
errors in the face of the presence of an additional bad signature.

GnuPG-bug-id: 4276
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
This commit is contained in:
Daniel Kahn Gillmor 2019-05-02 23:28:11 -04:00
parent bd2d282e57
commit 4100794e30
2 changed files with 10 additions and 13 deletions

View File

@ -342,10 +342,12 @@ class Context(GpgmeWrapper):
Decrypt the given ciphertext and verify any signatures. If Decrypt the given ciphertext and verify any signatures. If
VERIFY is an iterable of keys, the ciphertext must be signed VERIFY is an iterable of keys, the ciphertext must be signed
by all those keys, otherwise an error is raised. Note: if by all those keys, otherwise a MissingSignatures error is
VERIFY is an empty iterable, that is treated the same as raised. Note: if VERIFY is an empty iterable, that is treated
passing verify=True (that is, do verify signatures, but no the same as passing verify=True (that is, verify signatures
specific keys are required). and return data about any valid signatures found, but no
signatures are required and no MissingSignatures error will be
raised).
If the ciphertext is symmetrically encrypted using a If the ciphertext is symmetrically encrypted using a
passphrase, that passphrase can be given as parameter, using a passphrase, that passphrase can be given as parameter, using a
@ -361,11 +363,10 @@ class Context(GpgmeWrapper):
Returns: Returns:
plaintext -- the decrypted data (or None if sink is given) plaintext -- the decrypted data (or None if sink is given)
result -- additional information about the decryption result -- additional information about the decryption
verify_result -- additional information about the signature(s) verify_result -- additional information about the valid signature(s) found
Raises: Raises:
UnsupportedAlgorithm -- if an unsupported algorithm was used UnsupportedAlgorithm -- if an unsupported algorithm was used
BadSignatures -- if a bad signature is encountered
MissingSignatures -- if expected signatures are missing or bad MissingSignatures -- if expected signatures are missing or bad
GPGMEError -- as signaled by the underlying library GPGMEError -- as signaled by the underlying library
@ -430,13 +431,8 @@ class Context(GpgmeWrapper):
results=results) results=results)
if do_sig_verification: if do_sig_verification:
# FIXME: should we really throw BadSignature, even if # filter out all invalid signatures
# we've encountered some good signatures? as above, once verify_result.signatures = list(filter(lambda s: s.status == errors.NO_ERROR, verify_result.signatures))
# we hit this error, there is no way to accept it and
# continue to process the remaining signatures.
if any(s.status != errors.NO_ERROR
for s in verify_result.signatures):
raise errors.BadSignatures(verify_result, results=results)
if required_keys is not None: if required_keys is not None:
missing = [] missing = []
for key in required_keys: for key in required_keys:

View File

@ -84,5 +84,6 @@ with gpg.Context() as c:
plaintext, _, verify_result = c.decrypt(open(support.make_filename("cipher-3.asc"))) plaintext, _, verify_result = c.decrypt(open(support.make_filename("cipher-3.asc")))
assert len(plaintext) > 0 assert len(plaintext) > 0
assert len(verify_result.signatures) == 1
assert plaintext.find(b'Reenact Studied Thermos Bonehead Unclasp Opposing') >= 0, \ assert plaintext.find(b'Reenact Studied Thermos Bonehead Unclasp Opposing') >= 0, \
'second Plaintext not found' 'second Plaintext not found'