diff --git a/cmd/cosign/cli/attest/attest.go b/cmd/cosign/cli/attest/attest.go index 2380be6116a0..712d8a352947 100644 --- a/cmd/cosign/cli/attest/attest.go +++ b/cmd/cosign/cli/attest/attest.go @@ -33,8 +33,8 @@ import ( "github.com/sigstore/cosign/cmd/cosign/cli/sign" "github.com/sigstore/cosign/pkg/cosign" "github.com/sigstore/cosign/pkg/cosign/attestation" + cbundle "github.com/sigstore/cosign/pkg/cosign/bundle" cremote "github.com/sigstore/cosign/pkg/cosign/remote" - "github.com/sigstore/cosign/pkg/oci" "github.com/sigstore/cosign/pkg/oci/mutate" ociremote "github.com/sigstore/cosign/pkg/oci/remote" "github.com/sigstore/cosign/pkg/oci/static" @@ -46,25 +46,9 @@ import ( signatureoptions "github.com/sigstore/sigstore/pkg/signature/options" ) -// TODO(dekkagaijin): remove this in favor of a function in pkg which handles both signatures and attestations -func bundle(entry *models.LogEntryAnon) *oci.Bundle { - if entry.Verification == nil { - return nil - } - return &oci.Bundle{ - SignedEntryTimestamp: entry.Verification.SignedEntryTimestamp, - Payload: oci.BundlePayload{ - Body: entry.Body, - IntegratedTime: *entry.IntegratedTime, - LogIndex: *entry.LogIndex, - LogID: *entry.LogID, - }, - } -} - type tlogUploadFn func(*client.Rekor, []byte) (*models.LogEntryAnon, error) -func uploadToTlog(ctx context.Context, sv *sign.SignerVerifier, rekorURL string, upload tlogUploadFn) (*oci.Bundle, error) { +func uploadToTlog(ctx context.Context, sv *sign.SignerVerifier, rekorURL string, upload tlogUploadFn) (*cbundle.RekorBundle, error) { var rekorBytes []byte // Upload the cert or the public key, depending on what we have if sv.Cert != nil { @@ -86,7 +70,7 @@ func uploadToTlog(ctx context.Context, sv *sign.SignerVerifier, rekorURL string, return nil, err } fmt.Fprintln(os.Stderr, "tlog entry created with index:", *entry.LogIndex) - return bundle(entry), nil + return cbundle.EntryToBundle(entry), nil } //nolint diff --git a/internal/pkg/cosign/rekor/signer.go b/internal/pkg/cosign/rekor/signer.go index 46a8c39bb4ed..9293797df0af 100644 --- a/internal/pkg/cosign/rekor/signer.go +++ b/internal/pkg/cosign/rekor/signer.go @@ -24,37 +24,24 @@ import ( "github.com/sigstore/cosign/internal/pkg/cosign" cosignv1 "github.com/sigstore/cosign/pkg/cosign" + cbundle "github.com/sigstore/cosign/pkg/cosign/bundle" "github.com/sigstore/cosign/pkg/oci" "github.com/sigstore/cosign/pkg/oci/mutate" + "github.com/sigstore/rekor/pkg/generated/client" "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/sigstore/pkg/cryptoutils" ) -func bundle(entry *models.LogEntryAnon) *oci.Bundle { - if entry.Verification == nil { - return nil - } - return &oci.Bundle{ - SignedEntryTimestamp: entry.Verification.SignedEntryTimestamp, - Payload: oci.BundlePayload{ - Body: entry.Body, - IntegratedTime: *entry.IntegratedTime, - LogIndex: *entry.LogIndex, - LogID: *entry.LogID, - }, - } -} - type tlogUploadFn func(*client.Rekor, []byte) (*models.LogEntryAnon, error) -func uploadToTlog(rekorBytes []byte, rClient *client.Rekor, upload tlogUploadFn) (*oci.Bundle, error) { +func uploadToTlog(rekorBytes []byte, rClient *client.Rekor, upload tlogUploadFn) (*cbundle.RekorBundle, error) { entry, err := upload(rClient, rekorBytes) if err != nil { return nil, err } fmt.Fprintln(os.Stderr, "tlog entry created with index:", *entry.LogIndex) - return bundle(entry), nil + return cbundle.EntryToBundle(entry), nil } // signerWrapper calls a wrapped, inner signer then uploads either the Cert or Pub(licKey) of the results to Rekor, then adds the resulting `Bundle` diff --git a/pkg/cosign/bundle/rekor.go b/pkg/cosign/bundle/rekor.go new file mode 100644 index 000000000000..497aa7a464a6 --- /dev/null +++ b/pkg/cosign/bundle/rekor.go @@ -0,0 +1,46 @@ +// Copyright 2022 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bundle + +import "github.com/sigstore/rekor/pkg/generated/models" + +// RekorBundle holds metadata about recording a Signature's ephemeral key to +// a Rekor transparency log. +type RekorBundle struct { + SignedEntryTimestamp []byte + Payload RekorPayload +} + +type RekorPayload struct { + Body interface{} `json:"body"` + IntegratedTime int64 `json:"integratedTime"` + LogIndex int64 `json:"logIndex"` + LogID string `json:"logID"` +} + +func EntryToBundle(entry *models.LogEntryAnon) *RekorBundle { + if entry.Verification == nil { + return nil + } + return &RekorBundle{ + SignedEntryTimestamp: entry.Verification.SignedEntryTimestamp, + Payload: RekorPayload{ + Body: entry.Body, + IntegratedTime: *entry.IntegratedTime, + LogIndex: *entry.LogIndex, + LogID: *entry.LogID, + }, + } +} diff --git a/pkg/cosign/fetch.go b/pkg/cosign/fetch.go index 7f1ca14dfab6..c784b04c1046 100644 --- a/pkg/cosign/fetch.go +++ b/pkg/cosign/fetch.go @@ -24,10 +24,9 @@ import ( "github.com/google/go-containerregistry/pkg/name" "github.com/pkg/errors" - "knative.dev/pkg/pool" - - "github.com/sigstore/cosign/pkg/oci" + "github.com/sigstore/cosign/pkg/cosign/bundle" ociremote "github.com/sigstore/cosign/pkg/oci/remote" + "knative.dev/pkg/pool" ) type SignedPayload struct { @@ -35,7 +34,7 @@ type SignedPayload struct { Payload []byte Cert *x509.Certificate Chain []*x509.Certificate - Bundle *oci.Bundle + Bundle *bundle.RekorBundle } type Signatures struct { diff --git a/pkg/cosign/tlog.go b/pkg/cosign/tlog.go index b941dd0beca7..7ee0aa6c10bf 100644 --- a/pkg/cosign/tlog.go +++ b/pkg/cosign/tlog.go @@ -27,8 +27,8 @@ import ( "github.com/google/trillian/merkle/logverifier" "github.com/google/trillian/merkle/rfc6962" "github.com/pkg/errors" + "github.com/sigstore/cosign/pkg/cosign/bundle" "github.com/sigstore/cosign/pkg/cosign/tuf" - "github.com/sigstore/cosign/pkg/oci" "github.com/sigstore/rekor/pkg/generated/client/index" "github.com/sigstore/rekor/pkg/generated/client" @@ -262,7 +262,7 @@ func verifyTLogEntry(ctx context.Context, rekorClient *client.Rekor, uuid string return nil, errors.Wrap(err, "rekor public key pem to ecdsa") } - payload := oci.BundlePayload{ + payload := bundle.RekorPayload{ Body: e.Body, IntegratedTime: *e.IntegratedTime, LogIndex: *e.LogIndex, diff --git a/pkg/cosign/verify.go b/pkg/cosign/verify.go index f83d246be9c6..fbc4866e03fd 100644 --- a/pkg/cosign/verify.go +++ b/pkg/cosign/verify.go @@ -29,6 +29,8 @@ import ( "strings" "time" + cbundle "github.com/sigstore/cosign/pkg/cosign/bundle" + "github.com/sigstore/cosign/pkg/blob" "github.com/sigstore/cosign/pkg/oci/static" "github.com/sigstore/cosign/pkg/types" @@ -667,7 +669,7 @@ func bundleHash(bundleBody, signature string) (string, string, error) { return *hrekordObj.Data.Hash.Algorithm, *hrekordObj.Data.Hash.Value, nil } -func VerifySET(bundlePayload oci.BundlePayload, signature []byte, pub *ecdsa.PublicKey) error { +func VerifySET(bundlePayload cbundle.RekorPayload, signature []byte, pub *ecdsa.PublicKey) error { contents, err := json.Marshal(bundlePayload) if err != nil { return errors.Wrap(err, "marshaling") diff --git a/pkg/oci/internal/signature/layer.go b/pkg/oci/internal/signature/layer.go index 9091cc57ecdc..e042ce1a7db5 100644 --- a/pkg/oci/internal/signature/layer.go +++ b/pkg/oci/internal/signature/layer.go @@ -24,6 +24,7 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/pkg/errors" + "github.com/sigstore/cosign/pkg/cosign/bundle" "github.com/sigstore/cosign/pkg/oci" "github.com/sigstore/sigstore/pkg/cryptoutils" ) @@ -104,13 +105,13 @@ func (s *sigLayer) Chain() ([]*x509.Certificate, error) { } // Bundle implements oci.Signature -func (s *sigLayer) Bundle() (*oci.Bundle, error) { - bundle := s.desc.Annotations[BundleKey] - if bundle == "" { +func (s *sigLayer) Bundle() (*bundle.RekorBundle, error) { + val := s.desc.Annotations[BundleKey] + if val == "" { return nil, nil } - var b oci.Bundle - if err := json.Unmarshal([]byte(bundle), &b); err != nil { + var b bundle.RekorBundle + if err := json.Unmarshal([]byte(val), &b); err != nil { return nil, errors.Wrap(err, "unmarshaling bundle") } return &b, nil diff --git a/pkg/oci/internal/signature/layer_test.go b/pkg/oci/internal/signature/layer_test.go index 43f4eef17f78..a3ea0d80353d 100644 --- a/pkg/oci/internal/signature/layer_test.go +++ b/pkg/oci/internal/signature/layer_test.go @@ -26,7 +26,7 @@ import ( "github.com/google/go-containerregistry/pkg/v1/random" "github.com/google/go-containerregistry/pkg/v1/types" "github.com/pkg/errors" - "github.com/sigstore/cosign/pkg/oci" + "github.com/sigstore/cosign/pkg/cosign/bundle" ) func mustDecode(s string) []byte { @@ -57,7 +57,7 @@ func TestSignature(t *testing.T) { wantCertErr error wantChain int wantChainErr error - wantBundle *oci.Bundle + wantBundle *bundle.RekorBundle wantBundleErr error }{{ name: "just payload and signature", @@ -152,9 +152,9 @@ func TestSignature(t *testing.T) { }, }, wantSig: "blah", - wantBundle: &oci.Bundle{ + wantBundle: &bundle.RekorBundle{ SignedEntryTimestamp: mustDecode("MEUCIQClUkUqZNf+6dxBc/pxq22JIluTB7Kmip1G0FIF5E0C1wIgLqXm+IM3JYW/P/qjMZSXW+J8bt5EOqNfe3R+0A9ooFE="), - Payload: oci.BundlePayload{ + Payload: bundle.RekorPayload{ Body: "REMOVED", IntegratedTime: 1631646761, LogIndex: 693591, diff --git a/pkg/oci/mutate/options.go b/pkg/oci/mutate/options.go index f379779e3276..0c19f3da7f57 100644 --- a/pkg/oci/mutate/options.go +++ b/pkg/oci/mutate/options.go @@ -17,6 +17,7 @@ package mutate import ( "github.com/google/go-containerregistry/pkg/v1/types" + "github.com/sigstore/cosign/pkg/cosign/bundle" "github.com/sigstore/cosign/pkg/oci" ) @@ -60,7 +61,7 @@ func WithReplaceOp(ro ReplaceOp) SignOption { type signatureOpts struct { annotations map[string]string - bundle *oci.Bundle + bundle *bundle.RekorBundle cert []byte chain []byte mediaType types.MediaType @@ -76,9 +77,9 @@ func WithAnnotations(annotations map[string]string) SignatureOption { } // WithBundle specifies the new Bundle the Signature should have. -func WithBundle(bundle *oci.Bundle) SignatureOption { +func WithBundle(b *bundle.RekorBundle) SignatureOption { return func(so *signatureOpts) { - so.bundle = bundle + so.bundle = b } } diff --git a/pkg/oci/mutate/signature.go b/pkg/oci/mutate/signature.go index 3d0218555b5d..dd2a7ab68085 100644 --- a/pkg/oci/mutate/signature.go +++ b/pkg/oci/mutate/signature.go @@ -23,6 +23,7 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/types" "github.com/pkg/errors" + "github.com/sigstore/cosign/pkg/cosign/bundle" "github.com/sigstore/cosign/pkg/oci" "github.com/sigstore/cosign/pkg/oci/static" "github.com/sigstore/sigstore/pkg/cryptoutils" @@ -32,7 +33,7 @@ type sigWrapper struct { wrapped oci.Signature annotations map[string]string - bundle *oci.Bundle + bundle *bundle.RekorBundle cert *x509.Certificate chain []*x509.Certificate mediaType types.MediaType @@ -84,7 +85,7 @@ func (sw *sigWrapper) Chain() ([]*x509.Certificate, error) { } // Bundle implements oci.Signature. -func (sw *sigWrapper) Bundle() (*oci.Bundle, error) { +func (sw *sigWrapper) Bundle() (*bundle.RekorBundle, error) { if sw.bundle != nil { return sw.bundle, nil } diff --git a/pkg/oci/mutate/signature_test.go b/pkg/oci/mutate/signature_test.go index ca3cead43655..1e17e9bcf0bc 100644 --- a/pkg/oci/mutate/signature_test.go +++ b/pkg/oci/mutate/signature_test.go @@ -21,6 +21,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-containerregistry/pkg/v1/types" + "github.com/sigstore/cosign/pkg/cosign/bundle" "github.com/sigstore/cosign/pkg/oci" "github.com/sigstore/cosign/pkg/oci/static" ) @@ -290,9 +291,9 @@ func TestSignatureWithAnnotations(t *testing.T) { func TestSignatureWithBundle(t *testing.T) { payload := "this is the TestSignatureWithBundle content!" b64sig := "b64 content2=" - bundle := &oci.Bundle{ + b := &bundle.RekorBundle{ SignedEntryTimestamp: mustBase64Decode(t, "MEUCIQClUkUqZNf+6dxBc/pxq22JIluTB7Kmip1G0FIF5E0C1wIgLqXm+IM3JYW/P/qjMZSXW+J8bt5EOqNfe3R+0A9ooFE="), - Payload: oci.BundlePayload{ + Payload: bundle.RekorPayload{ Body: "REMOVED", IntegratedTime: 1631646761, LogIndex: 693591, @@ -300,9 +301,9 @@ func TestSignatureWithBundle(t *testing.T) { }, } originalSig := mustCreateSignature(t, []byte(payload), b64sig) - expectedSig := mustCreateSignature(t, []byte(payload), b64sig, static.WithBundle(bundle)) + expectedSig := mustCreateSignature(t, []byte(payload), b64sig, static.WithBundle(b)) - newSig, err := Signature(originalSig, WithBundle(bundle)) + newSig, err := Signature(originalSig, WithBundle(b)) if err != nil { t.Fatalf("Signature(WithBundle()) returned error: %v", err) } @@ -348,9 +349,9 @@ func TestSignatureWithEverything(t *testing.T) { "foo": "bar", "test": "yes", } - bundle := &oci.Bundle{ + b := &bundle.RekorBundle{ SignedEntryTimestamp: mustBase64Decode(t, "MEUCIQClUkUqZNf+6dxBc/pxq22JIluTB7Kmip1G0FIF5E0C1wIgLqXm+IM3JYW/P/qjMZSXW+J8bt5EOqNfe3R+0A9ooFE="), - Payload: oci.BundlePayload{ + Payload: bundle.RekorPayload{ Body: "REMOVED", IntegratedTime: 1631646761, LogIndex: 693591, @@ -363,13 +364,13 @@ func TestSignatureWithEverything(t *testing.T) { expectedSig := mustCreateSignature(t, []byte(payload), b64sig, static.WithAnnotations(annotations), - static.WithBundle(bundle), + static.WithBundle(b), static.WithCertChain(testCertBytes, testChainBytes), static.WithLayerMediaType(mediaType)) newSig, err := Signature(originalSig, WithAnnotations(annotations), - WithBundle(bundle), + WithBundle(b), WithCertChain(testCertBytes, testChainBytes), WithMediaType(mediaType)) diff --git a/pkg/oci/signatures.go b/pkg/oci/signatures.go index 82e473d56ea3..e66b7c6c9e1f 100644 --- a/pkg/oci/signatures.go +++ b/pkg/oci/signatures.go @@ -19,6 +19,7 @@ import ( "crypto/x509" v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/sigstore/cosign/pkg/cosign/bundle" ) // Signatures represents a set of signatures that are associated with a particular @@ -57,19 +58,5 @@ type Signature interface { // Bundle fetches the optional metadata that records the ephemeral // Fulcio key in the transparency log. - Bundle() (*Bundle, error) -} - -// Bundle holds metadata about recording a Signature's ephemeral key to -// a Rekor transparency log. -type Bundle struct { - SignedEntryTimestamp []byte - Payload BundlePayload -} - -type BundlePayload struct { - Body interface{} `json:"body"` - IntegratedTime int64 `json:"integratedTime"` - LogIndex int64 `json:"logIndex"` - LogID string `json:"logID"` + Bundle() (*bundle.RekorBundle, error) } diff --git a/pkg/oci/static/options.go b/pkg/oci/static/options.go index 4e067173d8b8..e00b6cdb4e5e 100644 --- a/pkg/oci/static/options.go +++ b/pkg/oci/static/options.go @@ -19,7 +19,7 @@ import ( "encoding/json" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/pkg/oci" + "github.com/sigstore/cosign/pkg/cosign/bundle" ctypes "github.com/sigstore/cosign/pkg/types" ) @@ -29,7 +29,7 @@ type Option func(*options) type options struct { LayerMediaType types.MediaType ConfigMediaType types.MediaType - Bundle *oci.Bundle + Bundle *bundle.RekorBundle Cert []byte Chain []byte Annotations map[string]string @@ -84,7 +84,7 @@ func WithAnnotations(ann map[string]string) Option { } // WithBundle sets the bundle to attach to the signature -func WithBundle(b *oci.Bundle) Option { +func WithBundle(b *bundle.RekorBundle) Option { return func(o *options) { o.Bundle = b } diff --git a/pkg/oci/static/options_test.go b/pkg/oci/static/options_test.go index 5a9ca66be6a1..63600c791ab7 100644 --- a/pkg/oci/static/options_test.go +++ b/pkg/oci/static/options_test.go @@ -21,12 +21,12 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/pkg/oci" + "github.com/sigstore/cosign/pkg/cosign/bundle" ctypes "github.com/sigstore/cosign/pkg/types" ) func TestOptions(t *testing.T) { - bundle := &oci.Bundle{} + bundle := &bundle.RekorBundle{} tests := []struct { name string diff --git a/pkg/oci/static/signature.go b/pkg/oci/static/signature.go index b987869754ed..882ff87e7df5 100644 --- a/pkg/oci/static/signature.go +++ b/pkg/oci/static/signature.go @@ -22,6 +22,7 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/types" + "github.com/sigstore/cosign/pkg/cosign/bundle" "github.com/sigstore/cosign/pkg/oci" "github.com/sigstore/sigstore/pkg/cryptoutils" ) @@ -105,7 +106,7 @@ func (l *staticLayer) Chain() ([]*x509.Certificate, error) { } // Bundle implements oci.Signature -func (l *staticLayer) Bundle() (*oci.Bundle, error) { +func (l *staticLayer) Bundle() (*bundle.RekorBundle, error) { return l.opts.Bundle, nil } diff --git a/pkg/oci/static/signature_test.go b/pkg/oci/static/signature_test.go index e6b031979777..1ef5beccb1db 100644 --- a/pkg/oci/static/signature_test.go +++ b/pkg/oci/static/signature_test.go @@ -24,7 +24,7 @@ import ( "github.com/google/go-cmp/cmp" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/pkg/oci" + "github.com/sigstore/cosign/pkg/cosign/bundle" ) func TestNewSignatureBasic(t *testing.T) { @@ -375,9 +375,9 @@ Ve/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uup Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ== -----END CERTIFICATE----- `) - bundle = &oci.Bundle{ + b = &bundle.RekorBundle{ SignedEntryTimestamp: mustDecode("MEUCIQClUkUqZNf+6dxBc/pxq22JIluTB7Kmip1G0FIF5E0C1wIgLqXm+IM3JYW/P/qjMZSXW+J8bt5EOqNfe3R+0A9ooFE="), - Payload: oci.BundlePayload{ + Payload: bundle.RekorPayload{ Body: "REMOVED", IntegratedTime: 1631646761, LogIndex: 693591, @@ -387,7 +387,7 @@ Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ== ) l, err := NewSignature([]byte(payload), b64sig, - WithCertChain(cert, chain), WithBundle(bundle)) + WithCertChain(cert, chain), WithBundle(b)) if err != nil { t.Fatalf("NewSignature() = %v", err) } @@ -411,8 +411,8 @@ Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ== if got, err := l.Bundle(); err != nil { t.Fatalf("Bundle() = %v", err) - } else if got != bundle { - t.Errorf("Bundle() = %#v, wanted %#v", got, bundle) + } else if got != b { + t.Errorf("Bundle() = %#v, wanted %#v", got, b) } if got, err := l.Cert(); err != nil {