secure-systems-lab / securesystemslib

Cryptographic and general-purpose routines for Secure Systems Lab projects at NYU

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How should I load signers for immediate signing, e.g. in CLI?

lukpueh opened this issue · comments

The currently recommended signer API usage pattern requires two steps to load a signer.

1. Take user inputs to load a public key and configure the signer URI
2. Take public key and signer URI to load a signer and sign

This separation of signer authorisation (e.g. delegate a key via TUF or in-toto metadata) and its usage is especially useful when the two steps are not performed in direct succession or not even on the same host.

However, the signer API may also be useful in a context, where the delegation happens out-of-band or after-the-fact. That is, the invocation is authorisation enough:

1. Take user inputs to load a signer and sign

Here, the separation from above is not intuitive nor efficient. The latter, because all current signing technologies in securesystemslib allow to infer the public key from the private key. Being forced to import the public key first, in order to then load the signer, adds unnecessary work (e.g. additional file read, network request, etc.)

Proposal

Add signer-specific API functions to load a signer including the public key material, e.g.:

class CryptoSigner(Signer):

    @classmethod
    def from_pem(private_bytes, keyid=None, scheme=None, password=None) -> CryptoSigner:
        """
        private_bytes: PKCS8/PEM private bytes
        keyid: use hex digest, if not passed
        scheme: use default for inferred key, if not passed
        password: treat as unencrytped, if not passed 
        """

I see no problems with this.

  • from_priv_key_uri() is generic but clumsy
  • likely all Signers could have more ergonomic signer-specific (or use-case-specific) constructors

I've never had a use-case where I wanted to avoid generic signer loading to have the latter but I can see others might.
Let's not add code "just because" but if an application use case gets easier by adding a constructor, let's do that.

likely all Signers could have more ergonomic signer-specific (or use-case-specific) constructors

Yes, a usable CryptoSigner.__init__ would already go a long way. Currently, CryptoSigner is abstract and all its subclasses are protected, which makes it unusable outside of from_priv_key_uri. If I could create a CryptoSigner from a pyca/cryptography private key object, then it would be easy for an application to create their own from_pem, e.g.:

from cryptography.hazmat.primitives.serialization import load_pem_private_key

private_key = load_pem_private_key(data, password)
signer = CryptoSigner(private_key)  # generate default public Key, if not passed explicitly