Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve API for signatures and subkeys #451

Open
wants to merge 259 commits into
base: master
Choose a base branch
from

Conversation

dkg
Copy link
Contributor

@dkg dkg commented Jun 15, 2023

On top of #450, this change makes the following API adjustments (from the diff in the changelog):

The following properties of PGPSignature now return None if the
corresponding subpacket is not present (they used to return an empty
string in that case):

* keyserver
* policy_uri
* signer
* signer_fingerprint

And the following properties of PGPSignature now return an
enum.IntFlag object instead of a set of custom FlagEnum objects.  When
the corresponding subpacket is not present at all, they return None:

* key_flags
* keyserverprefs
* features

PGPKey.subkeys now returns an OrderedDict indexed by Fingerprint
instead of KeyID.  When accessing this property via subscript (i.e.,
key.subkeys[x]), you can *also* index it by KeyID, but using a full
Fingerprint is recommended.

These underlying changes have a few advantages:

  • it is easier to reason about types,
  • it's possible to tell the difference between "no preference" and "an explicitly stated preference for nothing"
  • it is more likely that keys will be indexed and discovered without worrying about collisions on the (shorter) key ID.

dkg added 6 commits June 13, 2023 13:30
These tests are pulled from the OpenPGP Interoperability Test Suite,
in particular from those tests tagged "forward-compat":

   https://tests.sequoia-pgp.org/?q=forward-compat

These failures make it difficult to use PGPy in an OpenPGP ecosystem
that can evolve, because PGPy will complain about OpenPGP objects that
contain something it doesn't understand, even though the rest of the
message is otherwise comprehensible and usable.

See Justus Winter's message to openpgp@ietf.org describing his
concerns:

https://mailarchive.ietf.org/arch/msg/openpgp/QUiEKx3PQeJOXnkcvvnuHpv739M

I've selected specific examples that PGPy is known to currently fail with.
pgpy.types.Exportable was renamed to Armorable before version 0.3.0
was released (in d00010e, back in
2014), which indicates that this test program has not been run in over
8 years.

Given that the asyncio stuff has also changed in python since then, it
is simpler to just drop this file than try to fix it.
This reduces the number of SKIPPED and XFAIL messages from the test suite.

Given where the cleanup is happening, also make the remaining XFAIL messages
a little clearer.
This is not a signature subpacket.  Rather, it is a signature type.
@dkg dkg force-pushed the dkg/api-tuneup branch 4 times, most recently from 2dd79a7 to e2b7b8c Compare June 15, 2023 23:19
@dkg
Copy link
Contributor Author

dkg commented Jun 15, 2023

In addition to the API tune-up, with this PR applied, mypy pgpy returns no errors.

(mypy --strict pgpy still returns 1575 errors indicating that we don't have complete type coverage, but i'll work on fixing that in a subsequent PR)

@dkg dkg force-pushed the dkg/api-tuneup branch 2 times, most recently from b1f6827 to e028c80 Compare June 15, 2023 23:48
@dkg
Copy link
Contributor Author

dkg commented Jun 16, 2023

Given that #450 is still a WIP, this is also a WIP. I'll remove "WIP" when it is a bit more stable, but i wanted to make clear the specific API changes i'm considering making.

dkg and others added 16 commits June 16, 2023 17:33
It works in the basic mode, but we still need to handle the args for
encrypt/decrypt.
 - add enums for the flags passed into the sop interface

 - make member functions of StatelessOpenPGP well-typed

 - adjust docstrings so that help(sop) provides useful guidance

 - handle sessionkey and timestamp parsing in sop.py

 - handle all indirect access directly in sop.py

 - complete strict typing ("mypy --strict sop.py" passes)
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
By making all arguments to the functions keyword arguments, we can
use **kwargs to receive any extended options.

Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
This reflects the changes to the subcommand names and additional
arguments from draft-dkg-openpgp-stateless-cli-01
dkg added 21 commits August 11, 2023 14:26
…ithm

I don't expect new image encoding types to be defined.

Indeed, the version itself could just go away and we could probably retcon
UserAttribute 1 as JPEG (see
https://gitlab.com/openpgp-wg/rfc4880bis/-/issues/162) with a weird 16-octet header.

But it's better to have the code normalized here.
The implementation will select a reasonable option for the
indicated pubkey algorithm if you don't supply it.
This could be done only during the --profile
draft-ietf-openpgp-crypto-refresh-10, but there's nothing in the
earlier specifications that would indicate a problem or
incompatibility to include such a signature.
Move encrypt into fields.PubKey, and decrypt into fields.PrivKey.
This is a simplifying change, and also prepares the codebase for
the crypto-refresh, which has different subtle changes in the encoded
pkesk, for different versions and different algorithms.

The underlying cryptographic code gets pushed into fields.py (out of sight
from higher-level functions) and lets us make more straightforward and
explicit type definitions.
- if something is not implemented, just raise NotImplementedError
  directly, rather than trying to sometimes return a NotImplemented
  object.  Returning a NotImplemented object complicates the type
  signature without providing much of an advantage in terms of
  workflow.

- PGPSignature.target_signature is a property that was never
  implemented or used.  We can just drop this property entirely,
  implementing it only when it can actually be implemented.
use search_pref_sigs() instead of walking each user ID
This leaves only one place to list the requirements
@dkg dkg force-pushed the dkg/api-tuneup branch 2 times, most recently from 8558542 to ce54273 Compare August 18, 2023 18:43
This will be important if a non-v4 signature gets embedded.

It might end up being an opaque signature, if PGPy can't read the
version, but it shouldn't try to force a SignatureV4 if it is not
actually version 4.

This change also isolates the parsing of the embedded signature so that
it can only consume bytes within the enclosing subpacket.
This hasn't been necessary since fingerprints knew their own version,
it was just a no-op.
This is what caught the problem of passing _version to addnew
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants