From 806b18778e091f834396d6a0e8ad9de1078e3371 Mon Sep 17 00:00:00 2001 From: Vishal Choudhary Date: Mon, 18 Sep 2023 01:02:26 +0530 Subject: [PATCH 1/7] feat: add support outputting rekor response on signing Signed-off-by: Vishal Choudhary --- cmd/cosign/cli/sign/sign.go | 56 +++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/cmd/cosign/cli/sign/sign.go b/cmd/cosign/cli/sign/sign.go index 53c0fd3ccff..772c41e41a4 100644 --- a/cmd/cosign/cli/sign/sign.go +++ b/cmd/cosign/cli/sign/sign.go @@ -20,6 +20,7 @@ import ( "context" "crypto" "crypto/x509" + "encoding/json" "encoding/pem" "errors" "fmt" @@ -306,6 +307,31 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti ui.Infof(ctx, "Certificate wrote in the file %s", signOpts.OutputCertificate) } + if ko.BundlePath != "" { + rekorBytes, err := sv.Bytes(ctx) + if err != nil { + return fmt.Errorf("error getting signer: %w", err) + } + cert, err := cryptoutils.UnmarshalCertificatesFromPEM(rekorBytes) + + // signer is a certificate + if err == nil && len(cert) == 1 { + signedPayload, err := fetchSignedPayload(ociSig) + if err != nil { + return fmt.Errorf("failed to fetch signed payload: %w", err) + } + + contents, err := json.Marshal(signedPayload) + if err != nil { + return fmt.Errorf("failed to marshal signed payload: %w", err) + } + if err := os.WriteFile(ko.BundlePath, contents, 0600); err != nil { + return fmt.Errorf("create bundle file: %w", err) + } + ui.Infof(ctx, "Wrote bundle to file %s", ko.BundlePath) + } + } + if !signOpts.Upload { return nil } @@ -591,3 +617,33 @@ func (c *SignerVerifier) Bytes(ctx context.Context) ([]byte, error) { } return pemBytes, nil } + +func fetchSignedPayload(sig oci.Signature) (*cosign.SignedPayload, error) { + var signedPayload *cosign.SignedPayload + var err error + signedPayload.Payload, err = sig.Payload() + if err != nil { + return nil, err + } + signedPayload.Base64Signature, err = sig.Base64Signature() + if err != nil { + return nil, err + } + signedPayload.Cert, err = sig.Cert() + if err != nil { + return nil, err + } + signedPayload.Chain, err = sig.Chain() + if err != nil { + return nil, err + } + signedPayload.RFC3161Timestamp, err = sig.RFC3161Timestamp() + if err != nil { + return nil, err + } + signedPayload.Bundle, err = sig.Bundle() + if err != nil { + return nil, err + } + return signedPayload, nil +} From 42647246aeb54d4a7d5dc507b9b1c7d2ddcda60e Mon Sep 17 00:00:00 2001 From: Vishal Choudhary Date: Tue, 19 Sep 2023 18:57:52 +0530 Subject: [PATCH 2/7] feat: use local signed payload Signed-off-by: Vishal Choudhary --- cmd/cosign/cli/sign/sign.go | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/cmd/cosign/cli/sign/sign.go b/cmd/cosign/cli/sign/sign.go index 772c41e41a4..9c0b99009ef 100644 --- a/cmd/cosign/cli/sign/sign.go +++ b/cmd/cosign/cli/sign/sign.go @@ -20,6 +20,7 @@ import ( "context" "crypto" "crypto/x509" + "encoding/base64" "encoding/json" "encoding/pem" "errors" @@ -316,7 +317,7 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti // signer is a certificate if err == nil && len(cert) == 1 { - signedPayload, err := fetchSignedPayload(ociSig) + signedPayload, err := fetchLocalSignedPayload(ociSig) if err != nil { return fmt.Errorf("failed to fetch signed payload: %w", err) } @@ -618,26 +619,18 @@ func (c *SignerVerifier) Bytes(ctx context.Context) ([]byte, error) { return pemBytes, nil } -func fetchSignedPayload(sig oci.Signature) (*cosign.SignedPayload, error) { - var signedPayload *cosign.SignedPayload +func fetchLocalSignedPayload(sig oci.Signature) (*cosign.LocalSignedPayload, error) { + var signedPayload *cosign.LocalSignedPayload var err error - signedPayload.Payload, err = sig.Payload() - if err != nil { - return nil, err - } signedPayload.Base64Signature, err = sig.Base64Signature() if err != nil { return nil, err } - signedPayload.Cert, err = sig.Cert() - if err != nil { - return nil, err - } - signedPayload.Chain, err = sig.Chain() + sigCert, err := sig.Cert() if err != nil { return nil, err } - signedPayload.RFC3161Timestamp, err = sig.RFC3161Timestamp() + signedPayload.Cert = base64.StdEncoding.EncodeToString(sigCert.Raw) if err != nil { return nil, err } From 1a930ca641da844b3a5da5dc01f5a7c6e27d63e0 Mon Sep 17 00:00:00 2001 From: Vishal Choudhary Date: Tue, 19 Sep 2023 23:59:45 +0530 Subject: [PATCH 3/7] feat: add test Signed-off-by: Vishal Choudhary --- test/e2e_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/test/e2e_test.go b/test/e2e_test.go index 8df434a87a2..c243ba09a8d 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -951,6 +951,51 @@ func TestRekorBundle(t *testing.T) { must(verify(pubKeyPath, imgName, true, nil, ""), t) } +func TestRekorOutput(t *testing.T) { + // turn on the tlog + defer setenv(t, env.VariableExperimental.String(), "1")() + + repo, stop := reg(t) + defer stop() + td := t.TempDir() + + imgName := path.Join(repo, "cosign-e2e") + bundlePath := filepath.Join(td1, "bundle.sig") + + _, _, cleanup := mkimage(t, imgName) + defer cleanup() + + _, privKeyPath, pubKeyPath := keypair(t, td) + + ko := options.KeyOpts{ + KeyRef: privKeyPath, + PassFunc: passFunc, + RekorURL: rekorURL, + BundlePath: bundlePath, + } + so := options.SignOptions{ + Upload: true, + } + + // Sign the image + must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + // Make sure verify works + must(verify(pubKeyPath, imgName, true, nil, ""), t) + + if file, err := os.ReadFile(bundlePath); err != nil { + t.Fatal(err) + } else { + var localCosignPayload cosign.LocalSignedPayload + if err := json.Unmarshal(rekorBundleByte, &localCosignPayload); err != nil { + t.Fatal(err) + } + } + // Make sure offline verification works with bundling + // use rekor prod since we have hardcoded the public key + os.Setenv(serverEnv, "notreal") + must(verify(pubKeyPath, imgName, true, nil, ""), t) +} + func TestFulcioBundle(t *testing.T) { repo, stop := reg(t) defer stop() From b6d7c4657d71e7b52a6f520e66ac307711e1fd9c Mon Sep 17 00:00:00 2001 From: Vishal Choudhary Date: Wed, 20 Sep 2023 00:14:42 +0530 Subject: [PATCH 4/7] feat: test fix Signed-off-by: Vishal Choudhary --- test/e2e_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e_test.go b/test/e2e_test.go index c243ba09a8d..783f39260f7 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -960,7 +960,7 @@ func TestRekorOutput(t *testing.T) { td := t.TempDir() imgName := path.Join(repo, "cosign-e2e") - bundlePath := filepath.Join(td1, "bundle.sig") + bundlePath := filepath.Join(td, "bundle.sig") _, _, cleanup := mkimage(t, imgName) defer cleanup() @@ -986,7 +986,7 @@ func TestRekorOutput(t *testing.T) { t.Fatal(err) } else { var localCosignPayload cosign.LocalSignedPayload - if err := json.Unmarshal(rekorBundleByte, &localCosignPayload); err != nil { + if err := json.Unmarshal(file, &localCosignPayload); err != nil { t.Fatal(err) } } From 1c94f65621bb3add89b741c46fa877005a1907b4 Mon Sep 17 00:00:00 2001 From: Vishal Choudhary Date: Wed, 20 Sep 2023 01:03:25 +0530 Subject: [PATCH 5/7] fix: fetchLocalSignedPayload Signed-off-by: Vishal Choudhary --- cmd/cosign/cli/sign/sign.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cmd/cosign/cli/sign/sign.go b/cmd/cosign/cli/sign/sign.go index 9c0b99009ef..16942da4504 100644 --- a/cmd/cosign/cli/sign/sign.go +++ b/cmd/cosign/cli/sign/sign.go @@ -620,7 +620,7 @@ func (c *SignerVerifier) Bytes(ctx context.Context) ([]byte, error) { } func fetchLocalSignedPayload(sig oci.Signature) (*cosign.LocalSignedPayload, error) { - var signedPayload *cosign.LocalSignedPayload + signedPayload := &cosign.LocalSignedPayload{} var err error signedPayload.Base64Signature, err = sig.Base64Signature() if err != nil { @@ -630,9 +630,11 @@ func fetchLocalSignedPayload(sig oci.Signature) (*cosign.LocalSignedPayload, err if err != nil { return nil, err } - signedPayload.Cert = base64.StdEncoding.EncodeToString(sigCert.Raw) - if err != nil { - return nil, err + if sigCert != nil { + signedPayload.Cert = base64.StdEncoding.EncodeToString(sigCert.Raw) + if err != nil { + return nil, err + } } signedPayload.Bundle, err = sig.Bundle() if err != nil { From 533b5f5001eaeabb0d1338ce42f46bea2436a030 Mon Sep 17 00:00:00 2001 From: Vishal Choudhary Date: Wed, 20 Sep 2023 01:30:04 +0530 Subject: [PATCH 6/7] feat: update bundle output logic Signed-off-by: Vishal Choudhary --- cmd/cosign/cli/sign/sign.go | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/cmd/cosign/cli/sign/sign.go b/cmd/cosign/cli/sign/sign.go index 16942da4504..122aaa3339b 100644 --- a/cmd/cosign/cli/sign/sign.go +++ b/cmd/cosign/cli/sign/sign.go @@ -309,28 +309,19 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti } if ko.BundlePath != "" { - rekorBytes, err := sv.Bytes(ctx) + signedPayload, err := fetchLocalSignedPayload(ociSig) if err != nil { - return fmt.Errorf("error getting signer: %w", err) + return fmt.Errorf("failed to fetch signed payload: %w", err) } - cert, err := cryptoutils.UnmarshalCertificatesFromPEM(rekorBytes) - - // signer is a certificate - if err == nil && len(cert) == 1 { - signedPayload, err := fetchLocalSignedPayload(ociSig) - if err != nil { - return fmt.Errorf("failed to fetch signed payload: %w", err) - } - contents, err := json.Marshal(signedPayload) - if err != nil { - return fmt.Errorf("failed to marshal signed payload: %w", err) - } - if err := os.WriteFile(ko.BundlePath, contents, 0600); err != nil { - return fmt.Errorf("create bundle file: %w", err) - } - ui.Infof(ctx, "Wrote bundle to file %s", ko.BundlePath) + contents, err := json.Marshal(signedPayload) + if err != nil { + return fmt.Errorf("failed to marshal signed payload: %w", err) + } + if err := os.WriteFile(ko.BundlePath, contents, 0600); err != nil { + return fmt.Errorf("create bundle file: %w", err) } + ui.Infof(ctx, "Wrote bundle to file %s", ko.BundlePath) } if !signOpts.Upload { @@ -622,10 +613,12 @@ func (c *SignerVerifier) Bytes(ctx context.Context) ([]byte, error) { func fetchLocalSignedPayload(sig oci.Signature) (*cosign.LocalSignedPayload, error) { signedPayload := &cosign.LocalSignedPayload{} var err error + signedPayload.Base64Signature, err = sig.Base64Signature() if err != nil { return nil, err } + sigCert, err := sig.Cert() if err != nil { return nil, err @@ -635,7 +628,10 @@ func fetchLocalSignedPayload(sig oci.Signature) (*cosign.LocalSignedPayload, err if err != nil { return nil, err } + } else { + signedPayload.Cert = "" } + signedPayload.Bundle, err = sig.Bundle() if err != nil { return nil, err From 2f5402b29c2bb780a279b945ff37923c2ace464d Mon Sep 17 00:00:00 2001 From: Vishal Choudhary Date: Wed, 18 Oct 2023 00:23:29 +0530 Subject: [PATCH 7/7] feat: remove experimental flag Signed-off-by: Vishal Choudhary --- test/e2e_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/e2e_test.go b/test/e2e_test.go index 783f39260f7..8807023e7de 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -952,9 +952,6 @@ func TestRekorBundle(t *testing.T) { } func TestRekorOutput(t *testing.T) { - // turn on the tlog - defer setenv(t, env.VariableExperimental.String(), "1")() - repo, stop := reg(t) defer stop() td := t.TempDir()