diff --git a/cmd/cosign/cli/attest.go b/cmd/cosign/cli/attest.go index ce169d45454..d35356f7f7f 100644 --- a/cmd/cosign/cli/attest.go +++ b/cmd/cosign/cli/attest.go @@ -218,7 +218,9 @@ func AttestCmd(ctx context.Context, ko KeyOpts, imageRef string, certPath string } fmt.Fprintln(os.Stderr, "Pushing attestation to:", attRef.String()) - if _, err = cremote.UploadSignature(sig, payload, attRef, uo); err != nil { + // An attestation represents both the signature and payload. So store the entire thing + // in the payload field since they can get large + if _, err = cremote.UploadSignature([]byte{}, sig, attRef, uo); err != nil { return errors.Wrap(err, "uploading") } diff --git a/cmd/cosign/cli/verify_attestation.go b/cmd/cosign/cli/verify_attestation.go index f08ce645928..2130ae9e5ae 100644 --- a/cmd/cosign/cli/verify_attestation.go +++ b/cmd/cosign/cli/verify_attestation.go @@ -18,6 +18,7 @@ package cli import ( "context" "flag" + "io" "github.com/google/go-containerregistry/pkg/name" "github.com/peterbourgon/ff/v3/ffcli" @@ -93,6 +94,17 @@ EXAMPLES } } +// DSSE messages contain the signature and payload in one object, but our interface expects a signature and payload +// This means we need to use one field and ignore the other. The DSSE verifier upstream uses the signature field and ignores +// The message field, but we want the reverse here. +type reverseDSSEVerifier struct { + signature.Verifier +} + +func (w *reverseDSSEVerifier) VerifySignature(s io.Reader, m io.Reader, opts ...signature.VerifyOption) error { + return w.Verifier.VerifySignature(m, nil, opts...) +} + // Exec runs the verification command func (c *VerifyAttestationCommand) Exec(ctx context.Context, args []string) (err error) { if len(args) == 0 { @@ -134,7 +146,10 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, args []string) (err return errors.Wrap(err, "initializing piv token verifier") } } - co.SigVerifier = dsse.WrapVerifier(pubKey) + + co.SigVerifier = &reverseDSSEVerifier{ + Verifier: dsse.WrapVerifier(pubKey), + } for _, imageRef := range args { ref, err := name.ParseReference(imageRef) diff --git a/pkg/cosign/verifiers.go b/pkg/cosign/verifiers.go index 2ee2163668c..76aa8071842 100644 --- a/pkg/cosign/verifiers.go +++ b/pkg/cosign/verifiers.go @@ -16,10 +16,12 @@ package cosign import ( + "encoding/base64" "encoding/json" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/in-toto/in-toto-golang/in_toto" + "github.com/in-toto/in-toto-golang/pkg/ssl" "github.com/pkg/errors" "github.com/sigstore/sigstore/pkg/signature/payload" ) @@ -45,11 +47,20 @@ func SimpleClaimVerifier(sp SignedPayload, imageDigest v1.Hash, annotations map[ // IntotoSubjectClaimVerifier verifies that SignedPayload.Payload is an Intoto statement which references the given image digest. func IntotoSubjectClaimVerifier(sp SignedPayload, imageDigest v1.Hash, _ map[string]interface{}) error { - st := &in_toto.Statement{} - if err := json.Unmarshal(sp.Payload, st); err != nil { + // The payload here is an envelope. We already verified the signature earlier. + e := ssl.Envelope{} + if err := json.Unmarshal(sp.Payload, &e); err != nil { + return err + } + stBytes, err := base64.StdEncoding.DecodeString(e.Payload) + if err != nil { return err } + st := in_toto.Statement{} + if err := json.Unmarshal(stBytes, &st); err != nil { + return err + } for _, subj := range st.StatementHeader.Subject { dgst, ok := subj.Digest["sha256"] if !ok {