Skip to content

Commit

Permalink
Merge pull request #1605 from mtrmac/sigstore
Browse files Browse the repository at this point in the history
s/cosign/sigstore/
  • Loading branch information
mtrmac committed Jul 12, 2022
2 parents 229ccca + 409ab82 commit 29aec5f
Show file tree
Hide file tree
Showing 29 changed files with 388 additions and 388 deletions.
34 changes: 17 additions & 17 deletions copy/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,17 +123,17 @@ type ImageListSelection int

// Options allows supplying non-default configuration modifying the behavior of CopyImage.
type Options struct {
RemoveSignatures bool // Remove any pre-existing signatures. SignBy will still add a new signature.
SignBy string // If non-empty, asks for a signature to be added during the copy, and specifies a key ID, as accepted by signature.NewGPGSigningMechanism().SignDockerManifest(),
SignPassphrase string // Passphare to use when signing with the key ID from `SignBy`.
SignByCosignPrivateKeyFile string // If non-empty, asks for a signature to be added during the copy, using a Cosign private key file at the provided path.
SignCosignPrivateKeyPassphrase []byte // Passphare to use when signing with `SignByCosignPrivateKeyFile`.
SignIdentity reference.Named // Identify to use when signing, defaults to the docker reference of the destination
ReportWriter io.Writer
SourceCtx *types.SystemContext
DestinationCtx *types.SystemContext
ProgressInterval time.Duration // time to wait between reports to signal the progress channel
Progress chan types.ProgressProperties // Reported to when ProgressInterval has arrived for a single artifact+offset.
RemoveSignatures bool // Remove any pre-existing signatures. SignBy will still add a new signature.
SignBy string // If non-empty, asks for a signature to be added during the copy, and specifies a key ID, as accepted by signature.NewGPGSigningMechanism().SignDockerManifest(),
SignPassphrase string // Passphare to use when signing with the key ID from `SignBy`.
SignBySigstorePrivateKeyFile string // If non-empty, asks for a signature to be added during the copy, using a sigstore private key file at the provided path.
SignSigstorePrivateKeyPassphrase []byte // Passphare to use when signing with `SignBySigstorePrivateKeyFile`.
SignIdentity reference.Named // Identify to use when signing, defaults to the docker reference of the destination
ReportWriter io.Writer
SourceCtx *types.SystemContext
DestinationCtx *types.SystemContext
ProgressInterval time.Duration // time to wait between reports to signal the progress channel
Progress chan types.ProgressProperties // Reported to when ProgressInterval has arrived for a single artifact+offset.

// Preserve digests, and fail if we cannot.
PreserveDigests bool
Expand Down Expand Up @@ -577,8 +577,8 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
}
sigs = append(sigs, newSig)
}
if options.SignByCosignPrivateKeyFile != "" {
newSig, err := c.createCosignSignature(manifestList, options.SignByCosignPrivateKeyFile, options.SignCosignPrivateKeyPassphrase, options.SignIdentity)
if options.SignBySigstorePrivateKeyFile != "" {
newSig, err := c.createSigstoreSignature(manifestList, options.SignBySigstorePrivateKeyFile, options.SignSigstorePrivateKeyPassphrase, options.SignIdentity)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -697,7 +697,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
// We do intend the RecordDigestUncompressedPair calls to only work with reliable data, but at least there’s a risk
// that the compressed version coming from a third party may be designed to attack some other decompressor implementation,
// and we would reuse and sign it.
ic.canSubstituteBlobs = ic.cannotModifyManifestReason == "" && options.SignBy == "" && options.SignByCosignPrivateKeyFile == ""
ic.canSubstituteBlobs = ic.cannotModifyManifestReason == "" && options.SignBy == "" && options.SignBySigstorePrivateKeyFile == ""

if err := ic.updateEmbeddedDockerReference(); err != nil {
return nil, "", "", err
Expand Down Expand Up @@ -728,7 +728,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli

// If enabled, fetch and compare the destination's manifest. And as an optimization skip updating the destination iff equal
if options.OptimizeDestinationImageAlreadyExists {
shouldUpdateSigs := len(sigs) > 0 || options.SignBy != "" || options.SignByCosignPrivateKeyFile != "" // TODO: Consider allowing signatures updates only and skipping the image's layers/manifest copy if possible
shouldUpdateSigs := len(sigs) > 0 || options.SignBy != "" || options.SignBySigstorePrivateKeyFile != "" // TODO: Consider allowing signatures updates only and skipping the image's layers/manifest copy if possible
noPendingManifestUpdates := ic.noPendingManifestUpdates()

logrus.Debugf("Checking if we can skip copying: has signatures=%t, OCI encryption=%t, no manifest updates=%t", shouldUpdateSigs, destRequiresOciEncryption, noPendingManifestUpdates)
Expand Down Expand Up @@ -815,8 +815,8 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
}
sigs = append(sigs, newSig)
}
if options.SignByCosignPrivateKeyFile != "" {
newSig, err := c.createCosignSignature(manifestBytes, options.SignByCosignPrivateKeyFile, options.SignCosignPrivateKeyPassphrase, options.SignIdentity)
if options.SignBySigstorePrivateKeyFile != "" {
newSig, err := c.createSigstoreSignature(manifestBytes, options.SignBySigstorePrivateKeyFile, options.SignSigstorePrivateKeyPassphrase, options.SignIdentity)
if err != nil {
return nil, "", "", err
}
Expand Down
10 changes: 5 additions & 5 deletions copy/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/containers/image/v5/docker/reference"
internalsig "github.com/containers/image/v5/internal/signature"
"github.com/containers/image/v5/signature"
"github.com/containers/image/v5/signature/cosign"
"github.com/containers/image/v5/signature/sigstore"
"github.com/containers/image/v5/transports"
perrors "github.com/pkg/errors"
)
Expand Down Expand Up @@ -41,8 +41,8 @@ func (c *copier) createSignature(manifest []byte, keyIdentity string, passphrase
return internalsig.SimpleSigningFromBlob(newSig), nil
}

// createCosignSignature creates a new Cosign signature of manifest using privateKeyFile and identity.
func (c *copier) createCosignSignature(manifest []byte, privateKeyFile string, passphrase []byte, identity reference.Named) (internalsig.Signature, error) {
// createSigstoreSignature creates a new sigstore signature of manifest using privateKeyFile and identity.
func (c *copier) createSigstoreSignature(manifest []byte, privateKeyFile string, passphrase []byte, identity reference.Named) (internalsig.Signature, error) {
if identity != nil {
if reference.IsNameOnly(identity) {
return nil, fmt.Errorf("Sign identity must be a fully specified reference %s", identity.String())
Expand All @@ -54,8 +54,8 @@ func (c *copier) createCosignSignature(manifest []byte, privateKeyFile string, p
}
}

c.Printf("Signing manifest using Cosign\n")
newSig, err := cosign.SignDockerManifestWithPrivateKeyFileUnstable(manifest, identity, privateKeyFile, passphrase)
c.Printf("Signing manifest using a sigstore signature\n")
newSig, err := sigstore.SignDockerManifestWithPrivateKeyFileUnstable(manifest, identity, privateKeyFile, passphrase)
if err != nil {
return nil, fmt.Errorf("creating signature: %w", err)
}
Expand Down
38 changes: 19 additions & 19 deletions docker/docker_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ type dockerClient struct {
// by detectProperties(). Callers can edit tlsClientConfig.InsecureSkipVerify in the meantime.
tlsClientConfig *tls.Config
// The following members are not set by newDockerClient and must be set by callers if needed.
auth types.DockerAuthConfig
registryToken string
signatureBase lookasideStorageBase
useCosignAttachments bool
scope authScope
auth types.DockerAuthConfig
registryToken string
signatureBase lookasideStorageBase
useSigstoreAttachments bool
scope authScope

// The following members are detected registry properties:
// They are set after a successful detectProperties(), and never change afterwards.
Expand Down Expand Up @@ -236,7 +236,7 @@ func newDockerClientFromRef(sys *types.SystemContext, ref dockerReference, regis
client.registryToken = sys.DockerBearerRegistryToken
}
client.signatureBase = sigBase
client.useCosignAttachments = registryConfig.useCosignAttachments(ref)
client.useSigstoreAttachments = registryConfig.useSigstoreAttachments(ref)
client.scope.actions = actions
client.scope.remoteName = reference.Path(ref.ref)
return client, nil
Expand Down Expand Up @@ -933,36 +933,36 @@ func isManifestUnknownError(err error) bool {
return ec.ErrorCode() == v2.ErrorCodeManifestUnknown
}

// getCosignAttachmentManifest loads and parses the manifest for Cosign attachments for
// getSigstoreAttachmentManifest loads and parses the manifest for sigstore attachments for
// digest in ref.
// It returns (nil, nil) if the manifest does not exist.
func (c *dockerClient) getCosignAttachmentManifest(ctx context.Context, ref dockerReference, digest digest.Digest) (*manifest.OCI1, error) {
tag := cosignAttachmentTag(digest)
cosignRef, err := reference.WithTag(reference.TrimNamed(ref.ref), tag)
func (c *dockerClient) getSigstoreAttachmentManifest(ctx context.Context, ref dockerReference, digest digest.Digest) (*manifest.OCI1, error) {
tag := sigstoreAttachmentTag(digest)
sigstoreRef, err := reference.WithTag(reference.TrimNamed(ref.ref), tag)
if err != nil {
return nil, err
}
logrus.Debugf("Looking for Cosign attachments in %s", cosignRef.String())
logrus.Debugf("Looking for sigstore attachments in %s", sigstoreRef.String())
manifestBlob, mimeType, err := c.fetchManifest(ctx, ref, tag)
if err != nil {
// FIXME: Are we going to need better heuristics??
// This alone is probably a good enough reason for Cosign to be opt-in only,
// This alone is probably a good enough reason for sigstore to be opt-in only,
// otherwise we would just break ordinary copies.
if isManifestUnknownError(err) {
logrus.Debugf("Fetching Cosign attachment manifest failed, assuming it does not exist: %v", err)
logrus.Debugf("Fetching sigstore attachment manifest failed, assuming it does not exist: %v", err)
return nil, nil
}
logrus.Debugf("Fetching Cosign attachment manifest failed: %v", err)
logrus.Debugf("Fetching sigstore attachment manifest failed: %v", err)
return nil, err
}
if mimeType != imgspecv1.MediaTypeImageManifest {
// FIXME: Try anyway??
return nil, fmt.Errorf("unexpected MIME type for Cosign attachment manifest %s: %q",
cosignRef.String(), mimeType)
return nil, fmt.Errorf("unexpected MIME type for sigstore attachment manifest %s: %q",
sigstoreRef.String(), mimeType)
}
res, err := manifest.OCI1FromManifest(manifestBlob)
if err != nil {
return nil, fmt.Errorf("parsing manifest %s: %w", cosignRef.String(), err)
return nil, fmt.Errorf("parsing manifest %s: %w", sigstoreRef.String(), err)
}
return res, nil
}
Expand Down Expand Up @@ -993,7 +993,7 @@ func (c *dockerClient) getExtensionsSignatures(ctx context.Context, ref dockerRe
return &parsedBody, nil
}

// cosignAttachmentTag returns a Cosign attachment tag for the specified digest.
func cosignAttachmentTag(d digest.Digest) string {
// sigstoreAttachmentTag returns a sigstore attachment tag for the specified digest.
func sigstoreAttachmentTag(d digest.Digest) string {
return strings.Replace(d.String(), ":", "-", 1) + ".sig"
}
36 changes: 18 additions & 18 deletions docker/docker_image_dest.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,22 +531,22 @@ func (d *dockerImageDestination) PutSignaturesWithFormat(ctx context.Context, si
instanceDigest = &d.manifestDigest
}

cosignSignatures := []signature.Cosign{}
sigstoreSignatures := []signature.Sigstore{}
otherSignatures := []signature.Signature{}
for _, sig := range signatures {
if cosignSig, ok := sig.(signature.Cosign); ok {
cosignSignatures = append(cosignSignatures, cosignSig)
if sigstoreSig, ok := sig.(signature.Sigstore); ok {
sigstoreSignatures = append(sigstoreSignatures, sigstoreSig)
} else {
otherSignatures = append(otherSignatures, sig)
}
}

// Only write Cosign signatures to cosign attachments. We _could_ store them to lookaside
// Only write sigstores signatures to sigstores attachments. We _could_ store them to lookaside
// instead, but that would probably be rather surprising.
// FIXME: So should we enable cosign in all cases? Or write in all cases, but opt-in to read?
// FIXME: So should we enable sigstores in all cases? Or write in all cases, but opt-in to read?

if len(cosignSignatures) != 0 {
if err := d.putSignaturesToCosignAttachments(ctx, cosignSignatures, *instanceDigest); err != nil {
if len(sigstoreSignatures) != 0 {
if err := d.putSignaturesToSigstoreAttachments(ctx, sigstoreSignatures, *instanceDigest); err != nil {
return err
}
}
Expand Down Expand Up @@ -637,12 +637,12 @@ func (d *dockerImageDestination) putOneSignature(url *url.URL, sig signature.Sig
}
}

func (d *dockerImageDestination) putSignaturesToCosignAttachments(ctx context.Context, signatures []signature.Cosign, manifestDigest digest.Digest) error {
if !d.c.useCosignAttachments {
return errors.New("writing Cosign attachments is disabled by configuration")
func (d *dockerImageDestination) putSignaturesToSigstoreAttachments(ctx context.Context, signatures []signature.Sigstore, manifestDigest digest.Digest) error {
if !d.c.useSigstoreAttachments {
return errors.New("writing sigstore attachments is disabled by configuration")
}

ociManifest, err := d.c.getCosignAttachmentManifest(ctx, d.ref, manifestDigest)
ociManifest, err := d.c.getSigstoreAttachmentManifest(ctx, d.ref, manifestDigest)
if err != nil {
return nil
}
Expand All @@ -654,15 +654,15 @@ func (d *dockerImageDestination) putSignaturesToCosignAttachments(ctx context.Co
Size: 0,
}, nil)
} else {
logrus.Debugf("Fetching Cosign attachment config %s", ociManifest.Config.Digest.String())
logrus.Debugf("Fetching sigstore attachment config %s", ociManifest.Config.Digest.String())
// We don’t benefit from a real BlobInfoCache here because we never try to reuse/mount configs.
configBlob, err := d.c.getOCIDescriptorContents(ctx, d.ref, ociManifest.Config, iolimits.MaxConfigBodySize,
none.NoCache)
if err != nil {
return err
}
if err := json.Unmarshal(configBlob, &ociConfig); err != nil {
return fmt.Errorf("parsing Cosign attachment config %s in %s: %w", ociManifest.Config.Digest.String(),
return fmt.Errorf("parsing sigstore attachment config %s in %s: %w", ociManifest.Config.Digest.String(),
d.ref.ref.Name(), err)
}
}
Expand All @@ -674,7 +674,7 @@ func (d *dockerImageDestination) putSignaturesToCosignAttachments(ctx context.Co

alreadyOnRegistry := false
for _, layer := range ociManifest.Layers {
if layerMatchesCosignSignature(layer, mimeType, payloadBlob, annotations) {
if layerMatchesSigstoreSignature(layer, mimeType, payloadBlob, annotations) {
logrus.Debugf("Signature with digest %s already exists on the registry", layer.Digest.String())
alreadyOnRegistry = true
break
Expand Down Expand Up @@ -706,7 +706,7 @@ func (d *dockerImageDestination) putSignaturesToCosignAttachments(ctx context.Co
if err != nil {
return err
}
logrus.Debugf("Uploading updated Cosign attachment config")
logrus.Debugf("Uploading updated sigstore attachment config")
// We don’t benefit from a real BlobInfoCache here because we never try to reuse/mount configs.
configDesc, err := d.putBlobBytesAsOCI(ctx, configBlob, imgspecv1.MediaTypeImageConfig, private.PutBlobOptions{
Cache: none.NoCache,
Expand All @@ -723,11 +723,11 @@ func (d *dockerImageDestination) putSignaturesToCosignAttachments(ctx context.Co
if err != nil {
return nil
}
logrus.Debugf("Uploading Cosign attachment manifest")
return d.uploadManifest(ctx, manifestBlob, cosignAttachmentTag(manifestDigest))
logrus.Debugf("Uploading sigstore attachment manifest")
return d.uploadManifest(ctx, manifestBlob, sigstoreAttachmentTag(manifestDigest))
}

func layerMatchesCosignSignature(layer imgspecv1.Descriptor, mimeType string,
func layerMatchesSigstoreSignature(layer imgspecv1.Descriptor, mimeType string,
payloadBlob []byte, annotations map[string]string) bool {
if layer.MediaType != mimeType ||
layer.Size != int64(len(payloadBlob)) ||
Expand Down
18 changes: 9 additions & 9 deletions docker/docker_image_src.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,11 +415,11 @@ func (s *dockerImageSource) GetSignaturesWithFormat(ctx context.Context, instanc
return nil, errors.New("Internal error: X-Registry-Supports-Signatures extension not supported, and lookaside should not be empty configuration")
}

cosignSigs, err := s.getSignaturesFromCosignAttachments(ctx, instanceDigest)
sigstoreSigs, err := s.getSignaturesFromSigstoreAttachments(ctx, instanceDigest)
if err != nil {
return nil, err
}
res = append(res, cosignSigs...)
res = append(res, sigstoreSigs...)
return res, nil
}

Expand Down Expand Up @@ -537,9 +537,9 @@ func (s *dockerImageSource) getSignaturesFromAPIExtension(ctx context.Context, i
return sigs, nil
}

func (s *dockerImageSource) getSignaturesFromCosignAttachments(ctx context.Context, instanceDigest *digest.Digest) ([]signature.Signature, error) {
if !s.c.useCosignAttachments {
logrus.Debugf("Not looking for Cosign attachments: disabled by configuration")
func (s *dockerImageSource) getSignaturesFromSigstoreAttachments(ctx context.Context, instanceDigest *digest.Digest) ([]signature.Signature, error) {
if !s.c.useSigstoreAttachments {
logrus.Debugf("Not looking for sigstore attachments: disabled by configuration")
return nil, nil
}

Expand All @@ -548,20 +548,20 @@ func (s *dockerImageSource) getSignaturesFromCosignAttachments(ctx context.Conte
return nil, err
}

ociManifest, err := s.c.getCosignAttachmentManifest(ctx, s.physicalRef, manifestDigest)
ociManifest, err := s.c.getSigstoreAttachmentManifest(ctx, s.physicalRef, manifestDigest)
if err != nil {
return nil, err
}
if ociManifest == nil {
return nil, nil
}

logrus.Debugf("Found a Cosign attachment manifest with %d layers", len(ociManifest.Layers))
logrus.Debugf("Found a sigstore attachment manifest with %d layers", len(ociManifest.Layers))
res := []signature.Signature{}
for layerIndex, layer := range ociManifest.Layers {
// Note that this copies all kinds of attachments: attestations, and whatever else is there,
// not just signatures. We leave the signature consumers to decide based on the MIME type.
logrus.Debugf("Fetching Cosign attachment %d/%d: %s", layerIndex+1, len(ociManifest.Layers), layer.Digest.String())
logrus.Debugf("Fetching sigstore attachment %d/%d: %s", layerIndex+1, len(ociManifest.Layers), layer.Digest.String())
// We don’t benefit from a real BlobInfoCache here because we never try to reuse/mount attachment payloads.
// That might eventually need to change if payloads grow to be not just signatures, but something
// significantly large.
Expand All @@ -570,7 +570,7 @@ func (s *dockerImageSource) getSignaturesFromCosignAttachments(ctx context.Conte
if err != nil {
return nil, err
}
res = append(res, signature.CosignFromComponents(layer.MediaType, payload, layer.Annotations))
res = append(res, signature.SigstoreFromComponents(layer.MediaType, payload, layer.Annotations))
}
return res, nil
}
Expand Down

0 comments on commit 29aec5f

Please sign in to comment.