fix: copyObject key rotation issue (#10085)

- copyObject in-place decryption failed
  due to incorrect verification of headers
- do not decode ETag when object is encrypted
  with SSE-C, so that pre-conditions don't fail
  prematurely.
master
Harshavardhana 4 years ago committed by GitHub
parent 44c8af66ad
commit d53e560ce0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      cmd/bucket-policy.go
  2. 16
      cmd/encryption-v1.go
  3. 3
      cmd/object-api-utils.go
  4. 7
      cmd/object-handlers.go

@ -75,9 +75,6 @@ func getConditionValues(r *http.Request, lc string, username string, claims map[
if u, err := url.Parse(r.Header.Get(xhttp.AmzCopySource)); err == nil { if u, err := url.Parse(r.Header.Get(xhttp.AmzCopySource)); err == nil {
vid = u.Query().Get("versionId") vid = u.Query().Get("versionId")
} }
if vid == "" {
vid = r.Header.Get(xhttp.AmzCopySourceVersionID)
}
} }
args := map[string][]string{ args := map[string][]string{

@ -31,6 +31,7 @@ import (
"strings" "strings"
"github.com/minio/minio/cmd/crypto" "github.com/minio/minio/cmd/crypto"
xhttp "github.com/minio/minio/cmd/http"
"github.com/minio/minio/cmd/logger" "github.com/minio/minio/cmd/logger"
sha256 "github.com/minio/sha256-simd" sha256 "github.com/minio/sha256-simd"
"github.com/minio/sio" "github.com/minio/sio"
@ -809,9 +810,16 @@ func DecryptObjectInfo(info *ObjectInfo, r *http.Request) (encrypted bool, err e
} }
if encrypted { if encrypted {
if (crypto.SSEC.IsEncrypted(info.UserDefined) && !crypto.SSEC.IsRequested(headers)) || if crypto.SSEC.IsEncrypted(info.UserDefined) {
(crypto.S3.IsEncrypted(info.UserDefined) && crypto.SSEC.IsRequested(headers)) { if !(crypto.SSEC.IsRequested(headers) || crypto.SSECopy.IsRequested(headers)) {
return encrypted, errEncryptedObject return encrypted, errEncryptedObject
}
}
if crypto.S3.IsEncrypted(info.UserDefined) && r.Header.Get(xhttp.AmzCopySource) == "" {
if crypto.SSEC.IsRequested(headers) || crypto.SSECopy.IsRequested(headers) {
return encrypted, errEncryptedObject
}
} }
if _, err = info.DecryptedSize(); err != nil { if _, err = info.DecryptedSize(); err != nil {
@ -819,7 +827,7 @@ func DecryptObjectInfo(info *ObjectInfo, r *http.Request) (encrypted bool, err e
} }
if crypto.IsEncrypted(info.UserDefined) && !crypto.IsMultiPart(info.UserDefined) { if crypto.IsEncrypted(info.UserDefined) && !crypto.IsMultiPart(info.UserDefined) {
info.ETag = getDecryptedETag(headers, *info, headers.Get(crypto.SSECopyAlgorithm) != "") info.ETag = getDecryptedETag(headers, *info, false)
} }
} }

@ -612,7 +612,6 @@ func NewGetObjectReader(rs *HTTPRangeSpec, oi ObjectInfo, opts ObjectOptions, cl
} }
return nil, err return nil, err
} }
oi.ETag = getDecryptedETag(h, oi, copySource) // Decrypt the ETag before top layer consumes this value.
if opts.CheckPrecondFn != nil && opts.CheckPrecondFn(oi) { if opts.CheckPrecondFn != nil && opts.CheckPrecondFn(oi) {
// Call the cleanup funcs // Call the cleanup funcs
@ -622,6 +621,8 @@ func NewGetObjectReader(rs *HTTPRangeSpec, oi ObjectInfo, opts ObjectOptions, cl
return nil, PreConditionFailed{} return nil, PreConditionFailed{}
} }
oi.ETag = getDecryptedETag(h, oi, false)
// Apply the skipLen and limit on the // Apply the skipLen and limit on the
// decrypted stream // decrypted stream
decReader = io.LimitReader(ioutil.NewSkipReader(decReader, skipLen), decRangeLength) decReader = io.LimitReader(ioutil.NewSkipReader(decReader, skipLen), decRangeLength)

@ -612,10 +612,6 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re
// Set encryption response headers // Set encryption response headers
if objectAPI.IsEncryptionSupported() { if objectAPI.IsEncryptionSupported() {
if _, err = DecryptObjectInfo(&objInfo, r); err != nil {
writeErrorResponseHeadersOnly(w, toAPIError(ctx, err))
return
}
if crypto.IsEncrypted(objInfo.UserDefined) { if crypto.IsEncrypted(objInfo.UserDefined) {
switch { switch {
case crypto.S3.IsEncrypted(objInfo.UserDefined): case crypto.S3.IsEncrypted(objInfo.UserDefined):
@ -1744,9 +1740,6 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
// Note that url.Parse does the unescaping // Note that url.Parse does the unescaping
cpSrcPath = u.Path cpSrcPath = u.Path
} }
if vid == "" {
vid = strings.TrimSpace(r.Header.Get(xhttp.AmzCopySourceVersionID))
}
srcBucket, srcObject := path2BucketObject(cpSrcPath) srcBucket, srcObject := path2BucketObject(cpSrcPath)
// If source object is empty or bucket is empty, reply back invalid copy source. // If source object is empty or bucket is empty, reply back invalid copy source.

Loading…
Cancel
Save