From d2f8f8c7eee0d9976e2a31fb0c7c9170f2f51f9f Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Wed, 19 Dec 2018 14:12:53 -0800 Subject: [PATCH] Fix ETag handling with auto-encryption with CopyObject conditions (#7000) minio-java tests were failing under multiple places when auto encryption was turned on, handle all the cases properly This PR fixes - CopyObject should decrypt ETag before it does if-match - CopyObject should not try to preserve metadata of source when rotating keys, unless explicitly asked by the user. - We should not try to decrypt Compressed object etag, the potential case was if user sets encryption headers along with compression enabled. --- cmd/object-api-utils.go | 3 +++ cmd/object-handlers.go | 32 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/cmd/object-api-utils.go b/cmd/object-api-utils.go index 75e8efa37..8ba254cf3 100644 --- a/cmd/object-api-utils.go +++ b/cmd/object-api-utils.go @@ -503,6 +503,9 @@ func NewGetObjectReader(rs *HTTPRangeSpec, oi ObjectInfo, cleanUpFns ...func()) return nil, err } + // Decrypt the ETag before top layer consumes this value. + oi.ETag = getDecryptedETag(h, oi, copySource) + // Apply the skipLen and limit on the // decrypted stream decReader = io.LimitReader(ioutil.NewSkipReader(decReader, skipLen), decRangeLength) diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index 69a117b23..f53035df9 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -935,8 +935,11 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re return } } + for k, v := range srcInfo.UserDefined { - encMetadata[k] = v + if hasPrefix(k, ReservedMetadataPrefix) { + encMetadata[k] = v + } } // In case of SSE-S3 oldKey and newKey aren't used - the KMS manages the keys. @@ -1317,15 +1320,15 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req return } + etag := objInfo.ETag if objInfo.IsCompressed() { // Ignore compressed ETag. - objInfo.ETag = objInfo.ETag + "-1" - } - if hasServerSideEncryptionHeader(r.Header) { - w.Header().Set("ETag", "\""+getDecryptedETag(r.Header, objInfo, false)+"\"") - } else { - w.Header().Set("ETag", "\""+objInfo.ETag+"\"") + etag = objInfo.ETag + "-1" + } else if hasServerSideEncryptionHeader(r.Header) { + etag = getDecryptedETag(r.Header, objInfo, false) } + w.Header().Set("ETag", "\""+etag+"\"") + if objectAPI.IsEncryptionSupported() { if crypto.IsEncrypted(objInfo.UserDefined) { switch { @@ -1970,19 +1973,16 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) return } + + etag := partInfo.ETag if isCompressed { pipeWriter.Close() // Suppress compressed ETag. - partInfo.ETag = partInfo.ETag + "-1" - } - - if partInfo.ETag != "" { - if isEncrypted { - w.Header().Set("ETag", "\""+tryDecryptETag(objectEncryptionKey, partInfo.ETag, crypto.SSEC.IsRequested(r.Header))+"\"") - } else { - w.Header().Set("ETag", "\""+partInfo.ETag+"\"") - } + etag = partInfo.ETag + "-1" + } else if isEncrypted { + etag = tryDecryptETag(objectEncryptionKey, partInfo.ETag, crypto.SSEC.IsRequested(r.Header)) } + w.Header().Set("ETag", "\""+etag+"\"") writeSuccessResponseHeadersOnly(w) }