From 52e159e1c49dee5121411ab51968cb1779b7cb90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Greinhofer?= Date: Fri, 21 Jan 2022 13:35:55 -0600 Subject: [PATCH] Update verify-blob to support DSSEs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the ability to verify DSSEs from the `verify-blob` command. Fixes sigstore/cosign#1321 Signed-off-by: Rémy Greinhofer --- cmd/cosign/cli/verify/verify_blob.go | 23 +++++++++++ cmd/cosign/cli/verify/verify_blob_test.go | 48 +++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/cmd/cosign/cli/verify/verify_blob.go b/cmd/cosign/cli/verify/verify_blob.go index ada80f595f2..e4139a1793d 100644 --- a/cmd/cosign/cli/verify/verify_blob.go +++ b/cmd/cosign/cli/verify/verify_blob.go @@ -23,6 +23,7 @@ import ( _ "crypto/sha256" // for `crypto.SHA256` "crypto/x509" "encoding/base64" + "encoding/json" "fmt" "io" "os" @@ -30,6 +31,7 @@ import ( "github.com/go-openapi/runtime" "github.com/pkg/errors" + ssldsse "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/sigstore/cosign/cmd/cosign/cli/fulcio" "github.com/sigstore/cosign/cmd/cosign/cli/options" "github.com/sigstore/cosign/cmd/cosign/cli/rekor" @@ -39,12 +41,15 @@ import ( "github.com/sigstore/cosign/pkg/cosign/pivkey" "github.com/sigstore/cosign/pkg/cosign/pkcs11key" sigs "github.com/sigstore/cosign/pkg/signature" + + ctypes "github.com/sigstore/cosign/pkg/types" "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/types" hashedrekord "github.com/sigstore/rekor/pkg/types/hashedrekord/v0.0.1" rekord "github.com/sigstore/rekor/pkg/types/rekord/v0.0.1" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" + "github.com/sigstore/sigstore/pkg/signature/dsse" signatureoptions "github.com/sigstore/sigstore/pkg/signature/options" ) @@ -162,6 +167,11 @@ func VerifyBlobCmd(ctx context.Context, ko sign.KeyOpts, certRef, certEmail, cer } } + // Use the DSSE verifier if the payload is a DSSE with the In-Toto format. + if isIntotoDSSE(blobBytes) { + verifier = dsse.WrapVerifier(verifier) + } + // verify the signature if err := verifier.VerifySignature(bytes.NewReader([]byte(sig)), bytes.NewReader(blobBytes)); err != nil { return err @@ -348,3 +358,16 @@ func extractCerts(e *models.LogEntryAnon) ([]*x509.Certificate, error) { return certs, err } + +// isIntotoDSSE checks whether a payload is a Dead Simple Signing Envelope with the In-Toto format. +func isIntotoDSSE(blobBytes []byte) bool { + DSSEenvelope := ssldsse.Envelope{} + if err := json.Unmarshal(blobBytes, &DSSEenvelope); err != nil { + return false + } + if DSSEenvelope.PayloadType != ctypes.IntotoPayloadType { + return false + } + + return true +} diff --git a/cmd/cosign/cli/verify/verify_blob_test.go b/cmd/cosign/cli/verify/verify_blob_test.go index 683a8e426b1..faef49ad616 100644 --- a/cmd/cosign/cli/verify/verify_blob_test.go +++ b/cmd/cosign/cli/verify/verify_blob_test.go @@ -15,11 +15,13 @@ package verify import ( + "encoding/base64" "encoding/json" "io/ioutil" "path/filepath" "testing" + "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/sigstore/cosign/pkg/cosign" ) @@ -93,3 +95,49 @@ func TestSignaturesBundle(t *testing.T) { t.Fatalf("unexpected encoded signature, expected: %s got: %s", b64sig, gotb64Sig) } } + +func TestIsIntotoDSSEWithEnvelopes(t *testing.T) { + tts := []struct { + envelope dsse.Envelope + isIntotoDSSE bool + }{ + { + envelope: dsse.Envelope{ + PayloadType: "application/vnd.in-toto+json", + Payload: base64.StdEncoding.EncodeToString([]byte("This is a test")), + Signatures: []dsse.Signature{}, + }, + isIntotoDSSE: true, + }, + } + for _, tt := range tts { + envlopeBytes, _ := json.Marshal(tt.envelope) + got := isIntotoDSSE(envlopeBytes) + if got != tt.isIntotoDSSE { + t.Fatalf("unexpected envelope content") + } + } +} + +func TestIsIntotoDSSEWithBytes(t *testing.T) { + tts := []struct { + envelope []byte + isIntotoDSSE bool + }{ + { + envelope: []byte("This is no valid"), + isIntotoDSSE: false, + }, + { + envelope: []byte("MEUCIQDBmE1ZRFjUVic1hzukesJlmMFG1JqWWhcthnhawTeBNQIga3J9/WKsNlSZaySnl8V360bc2S8dIln2/qo186EfjHA="), + isIntotoDSSE: false, + }, + } + for _, tt := range tts { + envlopeBytes, _ := json.Marshal(tt.envelope) + got := isIntotoDSSE(envlopeBytes) + if got != tt.isIntotoDSSE { + t.Fatalf("unexpected envelope content") + } + } +}