sigstore / protobuf-specs

Protocol Buffer specifications
Apache License 2.0
23 stars 29 forks source link

Public keys as part of trust root #236

Open haydentherapper opened 9 months ago

haydentherapper commented 9 months ago

Currently the trust root specifies roots of trust from services (CA, CT log, Rekor, and TSA). For bring-your-own-PKI use cases where verifiers trust a set of keys, rather than certificates, it is not possible to specify the trusted keys via the trust root bundle. sigstore-go shows an example of adding trusted public keys to a parsed trust root, but this is not standardized across clients.

I propose adding repeated PublicKey public_keys (message) to the TrustedRoot message.

cc @kommendorkapten @codysoyland @woodruffw @bdehamer @loosebazooka

kommendorkapten commented 9 months ago

This was discussed earlier and decided against. My view is that raw public keys are to hard to manage on a "global level", such as in a trust root. What we have in the trust root today is "global services" only, i,e the CA, transparency log or the TSA. These are services that normally operate on a per environment level, which usually would translate into a single trust root.

Public keys on the other hand is more treated as an identity, and so they only are weakly referenced in the bundle (verifier is expected to have a key ring provided OOB). This would so identity the signer, compare this with how a certificate is embedded in the bundle to identity the signer.

For a certificate it's not enough to generally accept a signature from a signing certificate that chains up to a trusted certificate, we need to apply a policy too, that verifies things like SAN and issuer. These are properties part of the per artifact specific verification policy. This can be seen in the ArtifactVerificationOptions, the public keys are listed there, complete, not just the details on their algorithm, i.e values that can be used to actually verify a signature.

So I think the current design is as intended, as adding public keys to the trust root can open up to a situation were we would have a key-ring, but weak semantics around how they are supposed to be used, that would need an application layer to figure that out before verification can happen.

So IMHO we are not gaining anything by having the keys in the trust root, the client would still need to manage their key ring, collect the expected key given a policy for an artifact, then prepare the options and verify.

But you are raising a good question on unclarity of how to deal withpublic keys. I think we should document this, that clients using public keys are expected to bring their own keyring, manage a selection interface that may depend on the provided key hint to provide a key to use during verification and policy evaluation.

For npm we are doing this via a delegation in the TUF repo to provide the key-ring. That can be listed as one example on how to do it, many deployments probably have their own key-ring implementations already, so with proper documentation I think we can explain how to integrate them.

Thoughts?

haydentherapper commented 9 months ago

I think we should document this, that clients using public keys are expected to bring their own keyring, manage a selection interface that may depend on the provided key hint to provide a key to use during verification and policy evaluation.

Yea, this is the gap that I’ve noticed. Maybe another way to put it is, what are the required values in order to verify a signature? Currently, it’s the trust root, and either the identity of the signer or the public key.

I could envision a simple structure that is not meant for global verification values, but per-verification values including identity and keys. There may be some value in defining this so there’s consistency across clients and we mandate what is required for a verification event (eg identity means an identity plus an identity provider, using a key hint for a key ring).

Given that there are currently only two verification values, documentation could suffice for now without adding another struct.

haydentherapper commented 9 months ago

As you linked in the other thread on sigstore-go, https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_verification.proto#L92 is what I'm looking for in terms of a struct.

Part of my motivation for raising this was after looking at how we initialize a verifier in sigstore-go, that public keys are loaded into a trust root structure (not the same as trusted_root.proto), which feels strange given the proto does not define keys as part of its content. I think when clients start using the verification proto, this issue goes away.

I'm good to close this out once we add some documentation, that seems sufficient.

kommendorkapten commented 9 months ago

I'm good to close this out once we add some documentation, that seems sufficient.

That seems good. Do you think of a higher level document, like extend the readme with the different files and their purpose? I think that would help to onboard folks, and if needed add more documentation in each protobuf file too. I can take a look this week at extending the readme with a summary of what is documented in this repo if that sounds good.

haydentherapper commented 9 months ago

Yes, that sounds great! We can also link each file to steps in the client specification.