python: overhaul logic of Context.decrypt()

* lang/python/src/core.py (Context.decrypt): simplify and clarify the
logic behind handling verify=False.
* lang/python/tests/t-decrypt.py: ensure that we test verify=False

--

The function-internal variables were pretty unclear to the reader, and
the logic caused pretty nasty breakage when verify=False.

GnuPG-Bug-Id: 4271
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
This commit is contained in:
Daniel Kahn Gillmor 2018-12-04 20:44:35 +03:00
parent 5e21e61cfe
commit ac8d7238db
2 changed files with 36 additions and 34 deletions

View File

@ -370,8 +370,8 @@ class Context(GpgmeWrapper):
GPGMEError -- as signaled by the underlying library GPGMEError -- as signaled by the underlying library
""" """
sink_result = False do_sig_verification = False
verify_sigs = False required_keys = None
plaintext = sink if sink else Data() plaintext = sink if sink else Data()
if passphrase is not None: if passphrase is not None:
@ -385,22 +385,25 @@ class Context(GpgmeWrapper):
self.set_passphrase_cb(passphrase_cb) self.set_passphrase_cb(passphrase_cb)
try: try:
if verify is not None: if isinstance(verify, bool):
if isinstance(verify, bool) is True: do_sig_verification = verify
if verify is False: elif verify is None:
verify = True warnings.warn(
sink_result = True "ctx.decrypt called with verify=None, should be bool or iterable (treating as False).",
elif isinstance(verify, list) is True: category=DeprecationWarning)
if len(verify) > 0: do_sig_verification = False
verify_sigs = True else:
else: # we hope this is an iterable:
verify = True required_keys = verify
do_sig_verification = True
if do_sig_verification:
self.op_decrypt_verify(ciphertext, plaintext) self.op_decrypt_verify(ciphertext, plaintext)
else: else:
self.op_decrypt(ciphertext, plaintext) self.op_decrypt(ciphertext, plaintext)
except errors.GPGMEError as e: except errors.GPGMEError as e:
result = self.op_decrypt_result() result = self.op_decrypt_result()
if verify is not None and not sink_result: if do_sig_verification:
verify_result = self.op_verify_result() verify_result = self.op_verify_result()
else: else:
verify_result = None verify_result = None
@ -415,7 +418,7 @@ class Context(GpgmeWrapper):
result = self.op_decrypt_result() result = self.op_decrypt_result()
if verify is not None and not sink_result: if do_sig_verification:
verify_result = self.op_verify_result() verify_result = self.op_verify_result()
else: else:
verify_result = None verify_result = None
@ -426,7 +429,7 @@ class Context(GpgmeWrapper):
raise errors.UnsupportedAlgorithm(result.unsupported_algorithm, raise errors.UnsupportedAlgorithm(result.unsupported_algorithm,
results=results) results=results)
if verify: if do_sig_verification:
# FIXME: should we really throw BadSignature, even if # FIXME: should we really throw BadSignature, even if
# we've encountered some good signatures? as above, once # we've encountered some good signatures? as above, once
# we hit this error, there is no way to accept it and # we hit this error, there is no way to accept it and
@ -434,25 +437,24 @@ class Context(GpgmeWrapper):
if any(s.status != errors.NO_ERROR if any(s.status != errors.NO_ERROR
for s in verify_result.signatures): for s in verify_result.signatures):
raise errors.BadSignatures(verify_result, results=results) raise errors.BadSignatures(verify_result, results=results)
if required_keys is not None:
if verify_sigs: missing = []
missing = [] for key in required_keys:
for key in verify: ok = False
ok = False for subkey in key.subkeys:
for subkey in key.subkeys: for sig in verify_result.signatures:
for sig in verify_result.signatures: if sig.summary & constants.SIGSUM_VALID == 0:
if sig.summary & constants.SIGSUM_VALID == 0: continue
continue if subkey.can_sign and subkey.fpr == sig.fpr:
if subkey.can_sign and subkey.fpr == sig.fpr: ok = True
ok = True
break break
if ok: if ok:
break break
if not ok: if not ok:
missing.append(key) missing.append(key)
if missing: if missing:
raise errors.MissingSignatures(verify_result, missing, raise errors.MissingSignatures(verify_result, missing,
results=results) results=results)
return results return results

View File

@ -38,7 +38,7 @@ support.print_data(sink)
# Idiomatic interface. # Idiomatic interface.
with gpg.Context() as c: with gpg.Context() as c:
plaintext, _, _ = c.decrypt(open(support.make_filename("cipher-1.asc"))) plaintext, _, _ = c.decrypt(open(support.make_filename("cipher-1.asc")), verify=False)
assert len(plaintext) > 0 assert len(plaintext) > 0
assert plaintext.find(b'Wenn Sie dies lesen k') >= 0, \ assert plaintext.find(b'Wenn Sie dies lesen k') >= 0, \
'Plaintext not found' 'Plaintext not found'