secure-systems-lab / dsse

A specification for signing methods and formats used by Secure Systems Lab projects.
https://dsse.dev
Apache License 2.0
68 stars 18 forks source link

Add field for certificate chains, or explain alternative solution #42

Open MarkLodato opened 3 years ago

MarkLodato commented 3 years ago

(Forked from #39.)

There are several use cases for transmitting a certificate chain alongside the signature. We should either:

Personally I have no objections to adding a field, but I'd like to hear from others to explain what the concerns are.

/cc @trishankatdatadog @laurentsimon @shizhMSFT @gokarnm @TomHennen @dlorenc

trishankatdatadog commented 3 years ago

My concern is that if we slowly add more and more optional, unsigned fields like this, we risk accidentally turning DSSE into SSE (and eventually SE).

At the same time, I realize that this is a common use case with other signing envelopes, especially JWS. Maybe we could an add an optional attribute called "custom" or something similar, where people can stick in whatever extra metadata they like, such as cert chains, with the understanding that none of this stuff is signed. What do others think?

mikhailswift commented 3 years ago

The main issue with putting it in a custom field would be interoperability between applications using DSSE. An informal agreement would have to be made upon which custom field to use versus being able to refer to a standard.

trishankatdatadog commented 3 years ago

The main issue with putting it in a custom field would be interoperability between applications using DSSE. An informal agreement would have to be made upon which custom field to use versus being able to refer to a standard.

Right, my point is to agree (or not) on a standardized custom field under which you can store anything you like.

mikhailswift commented 3 years ago

I suppose when I hear "custom field" my mind jumps immediately to everyone doing it in slightly different incompatible ways. If we agree upon some specific custom field it's not much functionally different than adding the optional field to the spec from the spec's perspective.

Edit: I think by having a loose agreement on a specific field in a custom bag of fields instead of taking a hard opinion one way or the other the risk becomes making DSSE signatures more complex to use in practice for the sake of keeping the spec simple.

trishankatdatadog commented 3 years ago

I suppose when I hear "custom field" my mind jumps immediately to everyone doing it in slightly different incompatible ways. If we agree upon some specific custom field it's not much functionally different than adding the optional field to the spec from the spec's perspective.

Correct!

Edit: I think by having a loose agreement on a specific field in a custom bag of fields instead of taking a hard opinion one way or the other the risk becomes making DSSE signatures more complex to use in practice for the sake of keeping the spec simple.

I think it's taking a hard opinion in that we say here's your optional custom attribute living next to payloadType, payload, and signatures, and it's obviously unsigned payload. You can completely choose the ignore it, or reject it, or parse it according to application-specific logic.

But I can also see a hard opinion the other way saying, "nope, can do, bad idea for various good reasons." My concern here is that if people really want it, they will find a way around it (e.g., forking and extending DSSE, or maybe just use JWS I guess).

mikhailswift commented 3 years ago

I think it's taking a hard opinion in that we say here's your optional custom attribute living next to payloadType, payload, and signatures, and it's obviously unsigned payload. You can completely choose the ignore it, or reject it, or parse it according to application-specific logic.

As an end user of DSSE the value of adding the certificate chain to the spec would be that I could be assured any other application using DSSE would know how to use my certificate chain.

My concern here is that if people really want it, they will find a way around it (e.g., forking and extending DSSE, or maybe just use JWS I guess).

I think by taking the stance of “here’s a custom field you can use as you wish” invites all the negative aspects of fragmenting the spec that people forking or writing extensions would also carry.

Maybe the answer for solutions that need to transport a certificate chain alongside their signature is to just use JWS or a separate payload to transport the chain. @TomHennen had some ideas about a separate bundle that could be a good compromise here. Folks who need to transport their certificates along side their signature could implement this separate theoretical specification which leaves DSSE simple but still provides a common agreed upon format. Additionally certificate chains would only have to be sent once per key instead of once per signature.

However that does nothing to solve the worry of people forking or extending DSSE.

gokarnm commented 3 years ago

My concern is that if we slowly add more and more optional, unsigned fields like this, we risk accidentally turning DSSE into SSE (and eventually SE). At the same time, I realize that this is a common use case with other signing envelopes, especially JWS

I think there will be request from time to time for DSSE to add other fields which would be debated on a case by case basis and taken if it aligns with DSSE. It's not clear what aspects of DSSE design philosophy adding a field for cert chain would deviate from. Currently DSSE supports keyid which supports certain types of trust distribution schemes where client has access to fully a defined trust hierarchy (like Notary root.json). In X.509 certificates and related PKI which is used in a broad range of applications, this is not always the case, a client can use a leaf signing certificate, an intermediate or a root as their trust anchor (and will not have access to the signing cert before hand). Therefore signing cert is distributed with the signed artifact.

From Notary V2 stand point we only expect a top level unsigned attribute for TSA and Certificate chain. All other attributes including other custom attributes will be in the signed payload. I think this is a reasonable requirement if DSSE is used in similar context or application that uses X.509 certificates. I'd prefer a certificate field with defined semantics instead of a custom map.

As an end user of DSSE the value of adding the certificate chain to the spec would be that I could be assured any other application using DSSE would know how to use my certificate chain.

I think by taking the stance of “here’s a custom field you can use as you wish” invites all the negative aspects of fragmenting the spec that people forking or writing extensions would also carry.

Totally agree.

Additionally certificate chains would only have to be sent once per key instead of once per signature.

@mikhailswift, this does not work in cases like where short lived signing certificates are used to generate signatures, and the trust anchor is the issuer of these certificates, more context here.

MarkLodato commented 3 years ago

FWIW I have no objection to a cert field. To me it is the most straightforward option. @gokarnm and others have laid out a case for it.

I believe the arguments against are:

dlorenc commented 3 years ago

Anything that can be done as an unauthenticated top-level field could also be done as another data structure next to the DSSE envelope. Maybe it would be a good idea to iterate on the exact certificate semantics that way, then propose a merge into DSSE when the validation semantics and behavior are clearly defined and validated in some designs.

mnm678 commented 3 years ago

Could the keyid field be used to distribute the certificate chain? It is designed to be a 'hint' as to the key that should be used for verification, with the understanding that the client must verify this hint. The certificate chain is also a hint as to which key to use, though one that also includes the verification information.

This has the benefit of maintaining simplicity of DSSE, while allowing for multiple methods of delegation.

TomHennen commented 3 years ago

I like @dlorenc's idea. Is anyone planning to pursue this? Should this issue be assigned to them? :)

mikhailswift commented 3 years ago

I put some thought into it over last night and wouldn't putting something together

patricklawsongoogle commented 3 years ago

My two cents: it's better to just add the cert field. There is a need for this, it isn't novel, and AFAIK every other enveloping spec does the same thing. Developing this as sideband data "for a while" is in my opinion just inviting the same kind of fragmentation and forward-compatibility headaches of a free-for-all "custom" field where you can put whatever you want.

In fact, I would suggest that we specifically borrow the JWT field names and definitions here: x5c and x5t#S256 and possibly even x5u (if requested). The latter two address the problem of signature bloat if it's expected that the verifier can fetch the cert chain on their own given a sufficiently strong hint, and of course that the verifier is always ultimately verifying against their root of trust (e.g. CA public key).

If it really is concluded that we need a way to "beta test" fields in the protocol without guarantees of backwards compatibility, then to me that's a signal that we need to figure how to do that properly right now, whether it's with field naming conventions (e.g. prefix the field name with experimental- or whatever) or an opaque sideband object where you can stick whatever unsigned "stuff" that you want. But again, I think that's inviting fragmentation in a bad way.

I propose that we just try to make a standard, reasonable decision here, and if we need to walk that decision back in the future in a non-backwards-compatible way, then we rev the DSSE spec version (which is authenticated by PAE) and move on with our lives. That authenticated version is a major feature of the protocol: we should use it.

gokarnm commented 3 years ago

I agree with @patricklawsongoogle, the semantics of cert field are well understood, and demonstrated in other formats.

For Notary V2, we are contemplating extending DSSE with a cert field, but I'd rather spend time proposing changes, getting consensus here, and making it a part of the standard spec. By creating an extended field on top of DSSE we (Notary V2 use case) risk ending up with an incompatible format when cert is supported in DSSE spec.

MarkLodato commented 3 years ago

Would one of you care to create a pull request so that we have something more concrete to discuss? That might make it easier to reach consensus.

laurentsimon commented 3 years ago

Worry that implementations will blindly verify the sig against cert but not check that cert itself rolls up to a valid root CA. implementations of JWS and others have made this mistake. Valid concern, but it's not clear to me why having a different cert distribution mechanism would be any better in this regard.

I'm probably going on a tangent not exactly related to the original question (and I lack some of the context so my question may be obvious in retrospect), but: How is revocation handled when certs are used? Is the recipient assumed to fetch a CRL or make a request to an OCSP endpoint/CT log?

The reason I ask is that once revocation and cert verification are two distinct steps, implementations will provide knobs to select verification without revocation , and most devs will start using the insecure version of the API that accepts any cert (or use the in-band cert provided by an attacker) since it's the easiest shortcut to get tests working. TLS has had support for CRL for more than a decade, yet nobody has ever used them.. because it's so much easier to let the connection succeed (and the user happy). Certificate Transparency logs are the solution that finally made a dent into this problem. Why not build everything on top of a CT?

A CT makes the system auditable in one place and requires implementations to make a request to the CT to get the cert chain and the revocation status in one go. Most modern 'PKI' have this as a first-class citizen: sigstore and golang's signednote are examples.

If organization O1 signs artifact A1 with signature S1 and organization O2 wants to verify S2, why can O1 not upload their cert to a CT log? The only use case I can think of is if both entities only want to reveal their cert to each other but not the outside world? Is this common? Even in this case, both orgs can set up their own CT. I kinda feel that we should optimize for the common case, and not add complexity for the uncommon case.

As a developer, it's much harder to shot themselves in the foot with a CT log. Now they need to setup up a CT log themselves, somehow manage to pass the CT as anchor to the library, and they may still be detected by network scanner within the company because a port is open on some machine.

If, however, we have full control over implementations, then this problem could be fixed at the API level. Will that be the case?

I also think that DSSE spec and certificate discoverability/ownership/revocation are two distinct concepts. The latter needs the former but they should not be merged.

trishankatdatadog commented 3 years ago

I think @dlorenc and my current thinking are to solve this as a fork/extension to DSSE that does X.509 cert chains and maybe a few other things. Could be specific to Notary(?) / Notation v2. Best to keep DSSE simple.

dlorenc commented 3 years ago

I'd call it an extension or a wrapper. This argument is about layering and naming. What if we just wrap DSSE with another thing called "Dead Simple PKI Envelope"? DSSE is just for signatures, users that need PKI can wrap it in that layer.

We can separately think through the challenges of PKI, without complicating DSSE.

Even the basic "let's just add a cert" argument isn't as simple as it sounds. It adds another knob that needs to specified and reimplemented correctly. What if there's a cert and a public key set at the same time? Should clients treat this as invalid, or trust one over the other? Which one?

trishankatdatadog commented 3 years ago

Right. I'm not even a fan of including unsigned (well, not really, signed by any root in a whole local trust store of root bundles) cert chains, but that's a different story.

gokarnm commented 3 years ago

We can separately think through the challenges of PKI, without complicating DSSE.

@dlorenc, I agree there are complexities with PKI, though how do they complicate DSSE which is a signature format? IMHO DSSE does not dictate full details of how signature verification and key management should work, but attempts to influence it by following certain best practices that make it less likely to be misused, please correct if this is inaccurate. How is keyid any different than cert, keyid can be a reference to any key (or even a cert) in a key store/trust store, whose distribution mechanism, revocation support etc. are unknown and seem outside of DSSE's scope. As an example, you mentioned defining semantics if cert and public key (keyId ?) are both specified. Is the concern that this would be ambiguous to clients and different implementations may interpret it differently?

One of us working on signature format for Notary V2 (@priteshbandi, @shizhMSFT or me) can submit a PR, probably next week. I think we can start with a proposal which includes X.509 support in the base DSSE spec, and consider if it should be an extension instead once we debate the details in the PR.

laurentsimon commented 2 years ago

in case it has not been shared, cosign's bundle https://github.com/sigstore/cosign/blob/main/USAGE.md#verify-a-signature-was-added-to-the-transparency-log is a proposal to avoid rekor API calls during verification.

Note that it depends whether the verifier wants to checks for revoked certs. If you want to be sure sure the certs are not revoked, then an API call is always necessary, and the cert can be retrieved at the same time.

colek42 commented 1 year ago

I wanted to share that we've extended DSSE in our implementation in Witness, and you can check out the code at this link: https://github.com/testifysec/go-witness/blob/main/dsse/dsse.go#L56.

We believe that adding a cert chain and counter signature with TSA to the official spec is important, especially since best practices now dictate signing data with ephemeral keys. In our opinion, this feature is necessary to support this use case and ensure compatibility with other systems.

As we mentioned before, we believe that we need to move the spec forward to support this use case, or we may need to consider switching to another envelope that already supports these use cases in downstream projects that use DSSE. The lack of support for these use cases could limit interoperability and adoption, which is a major downside.

We're committed to finding the best solution for everyone and we're open to suggestions and feedback.

@dlorenc @mikhailswift @MarkLodato @SantiagoTorres @trishankatdatadog @adityasaky @JustinCappos

kommendorkapten commented 1 year ago

@colek42 Another option is to use the Sigstore bundle, which is a data structure that can capture a DSSE envelope, the X.509 certificate chain, an arbitrary number of TSA counter signatures and an arbitrary number of Rekor entries: https://github.com/sigstore/protobuf-specs/blob/bd2f3872848c66c4aee96c50f23717163e101e88/protos/sigstore_bundle.proto#L63

colek42 commented 1 year ago

@kommendorkapten While the sigstore bundle fulfills the required functionality, it adds an additional layer of complexity that could be avoided if DSSE incorporated fields for certificates and timestamps. Such an approach would simplify the process and reduce the potential for security vulnerabilities, as complexity is often seen as a hindrance to security.

mikhailswift commented 1 year ago

Something I'm not clear on with the sigstore bundle is how do you correlate specific x509 bundles or timestamps with specific signatures in the DSSE envelope?

MarkLodato commented 1 year ago

I support the proposal from @colek42.