Compare commits

...

6 Commits

Author SHA1 Message Date
Daniel Kahn Gillmor
ac8d7238db 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>
2018-12-05 02:41:16 +03:00
Daniel Kahn Gillmor
5e21e61cfe python: ctx.decrypt() has problematic error handling
* lang/python/src/core.py (Context.decrypt): document odd
error-handling behavior as a potential problem to be addressed.

Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2018-12-05 02:40:25 +03:00
Daniel Kahn Gillmor
fefa46173e python: Clarify the meaning of ctx.decrypt(verify=[])
* lang/python/src/core.py (Context.decrypt): docstring clarification
of what it means to pass an empty list to the verify argument.

Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2018-12-05 02:40:24 +03:00
Daniel Kahn Gillmor
30ddb2cabc python: gpg.Context.decrypt verify_sigs and sink_result are bools
Both of these function-internal variables are never used for anything
other than a binary state.  Implement them as the booleans they are.
Otherwise, casual readers of the code might think that they're
supposed to represent something other than a flag (e.g. "verify_sigs"
could mean "the signatures to verify", and "sink_result" could mean
"the place where we sink the result").

Signed-Off-By: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2018-12-05 02:40:24 +03:00
Daniel Kahn Gillmor
9a1903cc42 python: clarify documentation for verify argument for Context.decrypt()
It's easy to miss that verify can take a list of keys.  Make it more
obvious to the average python dev who reads docstrings.

Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2018-12-05 02:40:24 +03:00
Daniel Kahn Gillmor
827a2f3ad5 python: simplify Context.decrypt()
In the course of trying to address https://dev.gnupg.org/T4271, i
discovered that gpg.Context.decrypt() has a bit of superfluous code.
This changeset is intended to simplify the code without making any
functional changes.

Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2018-12-05 02:40:24 +03:00
2 changed files with 44 additions and 59 deletions

View File

@ -342,7 +342,10 @@ class Context(GpgmeWrapper):
Decrypt the given ciphertext and verify any signatures. If
VERIFY is an iterable of keys, the ciphertext must be signed
by all those keys, otherwise an error is raised.
by all those keys, otherwise an error is raised. Note: if
VERIFY is an empty iterable, that is treated the same as
passing verify=True (that is, do verify signatures, but no
specific keys are required).
If the ciphertext is symmetrically encrypted using a
passphrase, that passphrase can be given as parameter, using a
@ -352,7 +355,8 @@ class Context(GpgmeWrapper):
Keyword arguments:
sink -- write result to sink instead of returning it
passphrase -- for symmetric decryption
verify -- check signatures (default True)
verify -- check signatures (boolean or iterable of keys,
see above) (default True)
Returns:
plaintext -- the decrypted data (or None if sink is given)
@ -366,8 +370,8 @@ class Context(GpgmeWrapper):
GPGMEError -- as signaled by the underlying library
"""
sink_result = None
verify_sigs = None
do_sig_verification = False
required_keys = None
plaintext = sink if sink else Data()
if passphrase is not None:
@ -381,26 +385,25 @@ class Context(GpgmeWrapper):
self.set_passphrase_cb(passphrase_cb)
try:
if verify is not None:
if isinstance(verify, bool) is True:
if verify is False:
verify = True
sink_result = True
if isinstance(verify, bool):
do_sig_verification = verify
elif verify is None:
warnings.warn(
"ctx.decrypt called with verify=None, should be bool or iterable (treating as False).",
category=DeprecationWarning)
do_sig_verification = False
else:
pass
elif isinstance(verify, list) is True:
if len(verify) > 0:
verify_sigs = True
else:
pass
else:
verify = True
# we hope this is an iterable:
required_keys = verify
do_sig_verification = True
if do_sig_verification:
self.op_decrypt_verify(ciphertext, plaintext)
else:
self.op_decrypt(ciphertext, plaintext)
except errors.GPGMEError as e:
result = self.op_decrypt_result()
if verify is not None and sink_result is None:
if do_sig_verification:
verify_result = self.op_verify_result()
else:
verify_result = None
@ -415,7 +418,7 @@ class Context(GpgmeWrapper):
result = self.op_decrypt_result()
if verify is not None and sink_result is None:
if do_sig_verification:
verify_result = self.op_verify_result()
else:
verify_result = None
@ -426,14 +429,17 @@ class Context(GpgmeWrapper):
raise errors.UnsupportedAlgorithm(result.unsupported_algorithm,
results=results)
if verify:
if do_sig_verification:
# FIXME: should we really throw BadSignature, even if
# we've encountered some good signatures? as above, once
# 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 verify_sigs is not None:
if required_keys is not None:
missing = []
for key in verify:
for key in required_keys:
ok = False
for subkey in key.subkeys:
for sig in verify_result.signatures:
@ -447,29 +453,8 @@ class Context(GpgmeWrapper):
if not ok:
missing.append(key)
if missing:
try:
raise errors.MissingSignatures(verify_result, missing,
results=results)
except errors.MissingSignatures as e:
raise e
# mse = e
# mserr = "gpg.errors.MissingSignatures:"
# print(mserr, miss_e, "\n")
# # The full details can then be found in mse.results,
# # mse.result, mse.missing if necessary.
# mse_list = []
# msp = "Missing signatures from: \n".format()
# print(msp)
# for key in mse.missing:
# mse_list.append(key.fpr)
# msl = []
# msl.append(key.fpr)
# for user in key.uids:
# msl.append(user.name)
# msl.append(user.email)
# # msl.append(user.uid)
# print(" ".join(msl))
# raise mse
return results

View File

@ -38,7 +38,7 @@ support.print_data(sink)
# Idiomatic interface.
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 plaintext.find(b'Wenn Sie dies lesen k') >= 0, \
'Plaintext not found'