secure-systems-lab / securesystemslib

Cryptographic and general-purpose routines for Secure Systems Lab projects at NYU
MIT License
49 stars 49 forks source link

Revise module architecture and define clear API modules and functions #270

Closed lukpueh closed 7 months ago

lukpueh commented 4 years ago

Description of issue or feature request: Securesystemslib lacks of a clear public API. It should be clear and intuitive for users of secureystemslib, which modules and which functions are public API.

Current behavior: API is scattered across:

Expected behavior: Revise module architecture to use mnemonic names for (public) modules (not interface or functions) appropriate for the interface functions they contain. Also see discussion about import guidelines.

trishankatdatadog commented 4 years ago

💯 💯 💯

lukpueh commented 2 years ago

Following discussion in https://github.com/secure-systems-lab/securesystemslib/pull/409#issuecomment-1161469582 and recent developments related to the python-tuf v1 refactor, I suggest to shift signature-related API to Signer, Key, Signature classes, and making keys.{create, verify}_signature internal or deprecating them altogether once in-toto/tuf has migrated usage.

Why classes?

Details about these classes

More thoughts

lukpueh commented 2 years ago

We might want to consider replacing SslibSigner and SslibKey with less generic classes that are based on key types, and use polymorphism instead of long dispatch tables for behavior.

I am thinking of classes like RSASigner, Ed25519Signer, ECDSASigner (instead of SSlibSigner); and RSAKey, etc. (instead of SslibKey). Note that these could be very thin (opinionated) wrappers around the lower-level pyca/cryptography objects that we already use, e.g.:

from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey

class RSASigner(Signer):
    key: RSAPrivateKey
    ...

    def sign(self, payload: bytes) -> Signature:
      _sig = self.key.sign(payload, *opinionated_args)
      return Signature.from_pyca_crypto(_sig)

or with multi-inheritance

class RSASigner(Signer, RSAPrivateKey):
    ...
    def sign(self, payload: bytes) -> Signature:
      _sig = RSAPrivateKey.sign(self, payload, *opinionated_args)
      return Signature.from_pyca_crypto(_sig)

I think this could save many lines of abstraction-layer code in securesystemslib.

MVrachev commented 2 years ago

Overall the suggestions sound good.

On the topic of RSASigner example (as @lukpueh has already heard my opinion :D) I am not a fan of adding an inheritance just for the sake of simpler implementation without logical connection. In this example, I don't see a logical relationship between RSASigner and RSAPrivateKey. This of course is just my opinion and the maintainers should decide.

One minor naming suggestion - why don't we use SSlibSigner instead of SslibSigner? That's for all naming suggestions, I think double upper case S looks better.

lukpueh commented 2 years ago

One minor naming suggestion - why don't we use SSlibSigner instead of SslibSigner? That's for all naming suggestions, I think double upper case S looks better.

Agreed, the class in securesystemslib is actually called SSlibSigner. I'll update comments above...

lukpueh commented 2 years ago

In this example, I don't see a logical relationship between RSASigner and RSAPrivateKey.

The connection is that there is a 1-to-1 relationship between signing and private key (for tuf/in-toto), so it is possible to combine them in one class.

Of course, you could create an RSASigner class, which has an RSAPrivateKey attribute, but for our use case I don't see the benefit over having just one class that contains both the private key data and also has a sign method. You could call this one class either RSASigner or RSAPrivateKey, but for tuf/in-toto we care more about the signing aspect and less about the key aspect. Also, sometimes the signer isn't even a key, but just a reference to a key (e.g. GPGSigner - #341).

jku commented 2 years ago

my improvement ideas are in https://docs.google.com/document/d/1KQY5v1ASXpZM5GhfATV_WJf7GaMJrfBOXr06dtxc-ps/ but I'll summarize here -- just adding to what Lukas already listed. I believe this leads us to an API that is complete: users only need Key + Signer, there is no need to import any other securesystemslib modules.

Signer

Key

The core idea is: The specific implementations of Key and Signer are 99% implementation details that securesystemslib users should not need to know about. My understanding is that we can do that: the only exception will be key generation/import, which should be implementation specific.

jku commented 2 years ago

I tend to agree that smaller specific implementations (e.g. RSAKey) would be good but note that if we manage what is proposed above, it is only relevant to users for the specific case of key generation/import. Otherwise how the implementation is split is an implementation detail that we can change without breaking API.

lukpueh commented 7 months ago

731 has removed much of the legacy "API" in favour of securesystemslib.signer. IMO this new Signer API is relatively clear and well documented. Remaining documentation deficits are described in reasonably scoped issues (see "docs" label).

Apart from securesystemslib.signer we still have a few modules/subpackages, which don't fit in quite well, but also can't just be removed.