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

Support signing 'raw' in-toto statements #4019

Open
TomHennen opened this issue Jan 21, 2025 · 4 comments
Open

Support signing 'raw' in-toto statements #4019

TomHennen opened this issue Jan 21, 2025 · 4 comments
Labels
enhancement New feature or request

Comments

@TomHennen
Copy link
Contributor

Description

I'd like the ability to sign an in-toto Statement that I generate with other tooling with Sigstore and then later use Sigstore to verify the Signature on the attestation while leaving evaluation of the contents of the attestation to other custom tooling.

cosign currently supports signing arbitrary in-toto predicates via cosign attest-blob --predicate <FILE> --type <TYPE> -hash <HASH> ... (docs), but this does not work at the Statement layer.

That works well if the user doesn't need any control over the subject field beyond specifying the sha256 digest. However there are some cases (like signing the verification summary for the SLSA Source track), where the ability to use custom digests in the subject and to set annotations on subjects is required.

FWIW this capability has also been requested in gitsign but would be specific to git repos and would not support non-git usage. (There's also been a question raised of if it would be helpful to have this in a tool that is currently supported or not CC @steiza).

A nice workflow might look something like:

Generate

# Outputs an unsigned vuln predicate like https://github.com/in-toto/attestation/blob/main/spec/predicates/vulns_02.md
$ vuln_scan_repo github.com/foo/bar --output vulns.intoto.json.unsigned
Scanned COMMIT abc123
# Signs the statement using Sigstore, storing the results in a bundle for later use
$ cosign attest-blob --statement vulns.intoto.json.unsigned --bundle vulns.intoto.json

Use

# Check the signature...
$ cosign verify-blob-attestation --statement-only --bundle vulns.intoto.json --output-file vulns.intoto.json.unsigned
# Process the results, failing if there are any critical vulns
$ vuln_scan_check --no-critical vulns.intoto.json.unsigned
COMMIT abc123 PASS

FWIW verify-blob-attestation seems to require a blob to compute the digest itself, that won't be available in this case and should not be required.

@TomHennen TomHennen added the enhancement New feature or request label Jan 21, 2025
@codysoyland
Copy link
Member

codysoyland commented Jan 22, 2025

I mostly agree with this proposal -- the current behavior is too opinionated for many use-cases. It makes a lot of sense to offer the ability to pass an arbitrary statement to the attest-blob command.

The current implementation generates the statement based on a lot of hardcoded rules and per-predicate validation routines that honestly don't seem like cosign's responsibility. I do think some basic validation is good (must be valid json that can marshal to Statement type).

On the verification side, would it make sense to add a flag to specify a alg:digest pair to validate? I agree we shouldn't always require a file, but providing a digest is a good safeguard to make sure you're verifying the right material. In sigstore-go, we've been fairly opinionated that you should always provide an artifact or digest to validate against.

@TomHennen
Copy link
Contributor Author

I mostly agree with this proposal -- the current behavior is too opinionated for many use-cases. It makes a lot of sense to offer the ability to pass an arbitrary statement to the attest-blob command.

The current implementation generates the statement based on a lot of hardcoded rules and per-predicate validation routines that honestly don't seem like cosign's responsibility. I do think some basic validation is good (must be valid json that can marshal to Statement type).

On the verification side, would it make sense to add a flag to specify a alg:digest pair to validate? I agree we shouldn't always require a file, but providing a digest is a good safeguard to make sure you're verifying the right material. In sigstore-go, we've been fairly opinionated that you should always provide an artifact or digest to validate against.

That all makes sense to me, I could nitpick requiring a digest to verify against, what happens when Statement V2 comes out? It suddenly won't work because digests are computed separately? It also wouldn't allow for folks to sign other content in DSSE's with Sigstore which could be advantageous.

But... I don't have those problems now and what you propose would work fine. So if we can get something that works the way you describe that would be great.

@codysoyland
Copy link
Member

That all makes sense to me, I could nitpick requiring a digest to verify against, what happens when Statement V2 comes out? It suddenly won't work because digests are computed separately? It also wouldn't allow for folks to sign other content in DSSE's with Sigstore which could be advantageous.

The requirement to provide a file/digest comes down to preventing a footgun/confusion situation. Because bundles are a kind of detached signature, Cosign should attempt to bind the bundle to the artifact it references. The attack here would be something like a malicious binary is distributed with a valid bundle containing an attestation containing a subject digest that doesn't match the provided binary. Of course, the digest of the binary should be compared against the attestation to make sure it matches, and cosign is designed to bear that responsibility. A user with limited experience with cosign may assume it does that verification even if it doesn't, so we do this to prevent misuse.

Regarding Statement V2, I think we'd plan to continue to support any future in-toto statement versions (not sure what you mean by "digests are computed separately"). As for arbitrary DSSE content, this is currently unsupported and probably a broader discussion (could this be solved by using "raw" message signatures?).

I was also reading through issues this morning and noticed this PR which proposes adding the ability to add digest verification to verify-blob-attestation and there are some concerns raised about this idea so I highlighted your use-case there as well.

@haydentherapper
Copy link
Contributor

haydentherapper commented Jan 24, 2025

tl;dr: I'm supportive.

If I were to wave a magic CLI-making wand (I guess we call those LLMs now 🙃 ), I would prefer that Cosign and Sigstore SDKs not parse in-toto statements and only verify a provided signature (and certificate, log proof, etc), and that there exists a set of utilities to handle parsing and verifying DSSE envelopes and in-toto statements. For example, let's consider verifying a SLSA attestation:

  1. A SLSA verifier utility would delegate the parsing and verification of the in-toto statement to an in-toto library, and once that completes, verify the SLSA-specific in-toto predicate.
  2. An in-toto utility would delegate the parsing and verification of the DSSE envelope to a DSSE library, and once that completes, verify the in-toto subject and return the predicate.
  3. A DSSE utility would parse the DSSE, delegate verification of the DSSE signature to a Sigstore library, and once that completes, return the DSSE payload.
  4. Sigstore verification of the signature over the DSSE-provided PAE

With this structure, it becomes very easy to swap out envelopes or predicates simply by creating new utilities. Signing looks the same as well, with each utility responsible for constructing the inner envelope - Sigstore provides a sig/cert/proof, DSSE provides the envelope (and maybe places itself in the Sigstore bundle, but let's ignore that for now), in-toto provides the statement, SLSA populates the predicate.

With that said, because we don't have such a composable structure today, continuing to have Cosign be the one-stop-shop for signing and verifying in-toto statements seems reasonable. Cosign will be opinionated, but we should have the scope of that opinion be minimal - Cosign can assume it's signing an in-toto statement contained in a DSSE envelope, but nothing more.

I would be supportive of adding a flag to pass in an in-toto statement, and we can concurrently review the current state of attestation signing in Cosign and figure out what needs to be cleaned up as part of the next major revision of Cosign.

I think we've already hashed out verification in the other thread, very timely!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants