diff --git a/copy/blob.go b/copy/blob.go index 96674ddbb8..f45b97f56c 100644 --- a/copy/blob.go +++ b/copy/blob.go @@ -43,7 +43,7 @@ func (ic *imageCopier) copyBlobFromStream(ctx context.Context, srcReader io.Read stream.reader = bar.ProxyReader(stream.reader) // === Decrypt the stream, if required. - decryptionStep, err := ic.c.blobPipelineDecryptionStep(&stream, srcInfo) + decryptionStep, err := ic.blobPipelineDecryptionStep(&stream, srcInfo) if err != nil { return types.BlobInfo{}, err } @@ -78,7 +78,7 @@ func (ic *imageCopier) copyBlobFromStream(ctx context.Context, srcReader io.Read // Before relaxing this, see the original pull request’s review if there are other reasons to reject this. return types.BlobInfo{}, errors.New("Unable to support both decryption and encryption in the same copy") } - encryptionStep, err := ic.c.blobPipelineEncryptionStep(&stream, toEncrypt, srcInfo, decryptionStep) + encryptionStep, err := ic.blobPipelineEncryptionStep(&stream, toEncrypt, srcInfo, decryptionStep) if err != nil { return types.BlobInfo{}, err } diff --git a/copy/encryption.go b/copy/encryption.go index 54aca9e572..01d1ab79cb 100644 --- a/copy/encryption.go +++ b/copy/encryption.go @@ -33,12 +33,15 @@ type bpDecryptionStepData struct { // blobPipelineDecryptionStep updates *stream to decrypt if, it necessary. // srcInfo is only used for error messages. // Returns data for other steps; the caller should eventually use updateCryptoOperation. -func (c *copier) blobPipelineDecryptionStep(stream *sourceStream, srcInfo types.BlobInfo) (*bpDecryptionStepData, error) { - if isOciEncrypted(stream.info.MediaType) && c.ociDecryptConfig != nil { +func (ic *imageCopier) blobPipelineDecryptionStep(stream *sourceStream, srcInfo types.BlobInfo) (*bpDecryptionStepData, error) { + if isOciEncrypted(stream.info.MediaType) && ic.c.ociDecryptConfig != nil { + if ic.cannotModifyManifestReason != "" { + return nil, fmt.Errorf("layer %s should be decrypted, but we can’t modify the manifest: %s", srcInfo.Digest, ic.cannotModifyManifestReason) + } desc := imgspecv1.Descriptor{ Annotations: stream.info.Annotations, } - reader, decryptedDigest, err := ocicrypt.DecryptLayer(c.ociDecryptConfig, stream.reader, desc, false) + reader, decryptedDigest, err := ocicrypt.DecryptLayer(ic.c.ociDecryptConfig, stream.reader, desc, false) if err != nil { return nil, fmt.Errorf("decrypting layer %s: %w", srcInfo.Digest, err) } @@ -74,9 +77,13 @@ type bpEncryptionStepData struct { // blobPipelineEncryptionStep updates *stream to encrypt if, it required by toEncrypt. // srcInfo is primarily used for error messages. // Returns data for other steps; the caller should eventually call updateCryptoOperationAndAnnotations. -func (c *copier) blobPipelineEncryptionStep(stream *sourceStream, toEncrypt bool, srcInfo types.BlobInfo, +func (ic *imageCopier) blobPipelineEncryptionStep(stream *sourceStream, toEncrypt bool, srcInfo types.BlobInfo, decryptionStep *bpDecryptionStepData) (*bpEncryptionStepData, error) { - if toEncrypt && !isOciEncrypted(srcInfo.MediaType) && c.ociEncryptConfig != nil { + if toEncrypt && !isOciEncrypted(srcInfo.MediaType) && ic.c.ociEncryptConfig != nil { + if ic.cannotModifyManifestReason != "" { + return nil, fmt.Errorf("layer %s should be encrypted, but we can’t modify the manifest: %s", srcInfo.Digest, ic.cannotModifyManifestReason) + } + var annotations map[string]string if !decryptionStep.decrypting { annotations = srcInfo.Annotations @@ -87,7 +94,7 @@ func (c *copier) blobPipelineEncryptionStep(stream *sourceStream, toEncrypt bool Size: srcInfo.Size, Annotations: annotations, } - reader, finalizer, err := ocicrypt.EncryptLayer(c.ociEncryptConfig, stream.reader, desc) + reader, finalizer, err := ocicrypt.EncryptLayer(ic.c.ociEncryptConfig, stream.reader, desc) if err != nil { return nil, fmt.Errorf("encrypting blob %s: %w", srcInfo.Digest, err) }