diff --git a/copy/copy.go b/copy/copy.go index 9837972c53..b616e566cb 100644 --- a/copy/copy.go +++ b/copy/copy.go @@ -124,10 +124,10 @@ 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`. - SignIdentity string // Identify to use when signing, defaults to the docker reference of the destination + 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`. + 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 diff --git a/copy/sign.go b/copy/sign.go index 0c203c29fb..4ebd484031 100644 --- a/copy/sign.go +++ b/copy/sign.go @@ -1,13 +1,14 @@ package copy import ( + "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/signature" "github.com/containers/image/v5/transports" "github.com/pkg/errors" ) // createSignature creates a new signature of manifest using keyIdentity. -func (c *copier) createSignature(manifest []byte, keyIdentity string, passphrase string, identity string) ([]byte, error) { +func (c *copier) createSignature(manifest []byte, keyIdentity string, passphrase string, identity reference.Named) ([]byte, error) { mech, err := signature.NewGPGSigningMechanism() if err != nil { return nil, errors.Wrap(err, "initializing GPG") @@ -17,16 +18,19 @@ func (c *copier) createSignature(manifest []byte, keyIdentity string, passphrase return nil, errors.Wrap(err, "Signing not supported") } - if identity == "" { - dockerReference := c.dest.Reference().DockerReference() - if dockerReference == nil { + if identity != nil { + if reference.IsNameOnly(identity) { + return nil, errors.Errorf("Sign identity must be full a fully specified reference %s", identity) + } + } else { + identity = c.dest.Reference().DockerReference() + if identity == nil { return nil, errors.Errorf("Cannot determine canonical Docker reference for destination %s", transports.ImageName(c.dest.Reference())) } - identity = dockerReference.String() } c.Printf("Signing manifest\n") - newSig, err := signature.SignDockerManifestWithOptions(manifest, identity, mech, keyIdentity, &signature.SignOptions{Passphrase: passphrase}) + newSig, err := signature.SignDockerManifestWithOptions(manifest, identity.String(), mech, keyIdentity, &signature.SignOptions{Passphrase: passphrase}) if err != nil { return nil, errors.Wrap(err, "creating signature") } diff --git a/copy/sign_test.go b/copy/sign_test.go index 5f44cad621..1e9fc6738b 100644 --- a/copy/sign_test.go +++ b/copy/sign_test.go @@ -12,6 +12,7 @@ import ( "github.com/containers/image/v5/manifest" "github.com/containers/image/v5/signature" "github.com/containers/image/v5/types" + "github.com/docker/distribution/reference" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -49,7 +50,7 @@ func TestCreateSignature(t *testing.T) { dest: imagedestination.FromPublic(dirDest), reportWriter: ioutil.Discard, } - _, err = c.createSignature(manifestBlob, testKeyFingerprint, "", "") + _, err = c.createSignature(manifestBlob, testKeyFingerprint, "", nil) assert.Error(t, err) // Set up a docker: reference @@ -65,14 +66,22 @@ func TestCreateSignature(t *testing.T) { } // Signing with an unknown key fails - _, err = c.createSignature(manifestBlob, "this key does not exist", "", "") + _, err = c.createSignature(manifestBlob, "this key does not exist", "", nil) assert.Error(t, err) - // Signing without overriding the identity uses the docker reference + // Can't sign without a full reference + ref, err := reference.ParseNamed("myregistry.io/myrepo") + require.NoError(t, err) + _, err = c.createSignature(manifestBlob, testKeyFingerprint, "", ref) + assert.Error(t, err) + + // Mechanism for verifying the signatures mech, err = signature.NewGPGSigningMechanism() require.NoError(t, err) defer mech.Close() - sig, err := c.createSignature(manifestBlob, testKeyFingerprint, "", "") + + // Signing without overriding the identity uses the docker reference + sig, err := c.createSignature(manifestBlob, testKeyFingerprint, "", nil) require.NoError(t, err) verified, err := signature.VerifyDockerManifestSignature(sig, manifestBlob, "docker.io/library/busybox:latest", mech, testKeyFingerprint) require.NoError(t, err) @@ -80,10 +89,9 @@ func TestCreateSignature(t *testing.T) { assert.Equal(t, manifestDigest, verified.DockerManifestDigest) // Can override the identity with own - mech, err = signature.NewGPGSigningMechanism() + ref, err = reference.ParseNamed("myregistry.io/myrepo:mytag") require.NoError(t, err) - defer mech.Close() - sig, err = c.createSignature(manifestBlob, testKeyFingerprint, "", "myregistry.io/myrepo:mytag") + sig, err = c.createSignature(manifestBlob, testKeyFingerprint, "", ref) require.NoError(t, err) verified, err = signature.VerifyDockerManifestSignature(sig, manifestBlob, "myregistry.io/myrepo:mytag", mech, testKeyFingerprint) require.NoError(t, err)