diff --git a/cmd/api-errors.go b/cmd/api-errors.go index 8e2d08bed..f0ffb28d6 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -706,6 +706,8 @@ func toAPIErrorCode(err error) (apiErr APIErrorCode) { apiErr = ErrNoSuchUpload case PartTooSmall: apiErr = ErrEntityTooSmall + case SignatureDoesNotMatch: + apiErr = ErrSignatureDoesNotMatch case SHA256Mismatch: apiErr = ErrContentSHA256Mismatch case ObjectTooLarge: diff --git a/cmd/gateway-gcs.go b/cmd/gateway-gcs.go index 23fd946ce..8d1010191 100644 --- a/cmd/gateway-gcs.go +++ b/cmd/gateway-gcs.go @@ -35,6 +35,8 @@ import ( "encoding/base64" + "bytes" + minio "github.com/minio/minio-go" "github.com/minio/minio-go/pkg/policy" ) @@ -469,17 +471,18 @@ func (l *gcsGateway) PutObject(bucket string, key string, size int64, data io.Re return ObjectInfo{}, gcsToObjectError(traceError(err), bucket) } - var sha256Writer hash.Hash - teeReader := data + + var sha256Writer hash.Hash if sha256sum == "" { } else if _, err := hex.DecodeString(sha256sum); err != nil { return ObjectInfo{}, gcsToObjectError(traceError(err), bucket, key) } else { sha256Writer = sha256.New() - teeReader = io.TeeReader(data, sha256Writer) + teeReader = io.TeeReader(teeReader, sha256Writer) } + md5sum := metadata["md5Sum"] delete(metadata, "md5Sum") object := l.client.Bucket(bucket).Object(key) @@ -504,12 +507,18 @@ func (l *gcsGateway) PutObject(bucket string, key string, size int64, data io.Re if err != nil { return ObjectInfo{}, gcsToObjectError(traceError(err), bucket, key) } - if sha256sum != "" { - newSHA256sum := hex.EncodeToString(sha256Writer.Sum(nil)) - if newSHA256sum != sha256sum { - //l.Client.RemoveObject(bucket, object) - return ObjectInfo{}, traceError(SHA256Mismatch{}) - } + + if sha256sum == "" { + } else if newSHA256sum := hex.EncodeToString(sha256Writer.Sum(nil)); newSHA256sum != sha256sum { + object.Delete(l.ctx) + return ObjectInfo{}, traceError(SHA256Mismatch{}) + } + + if md5sum == "" { + } else if b, err := hex.DecodeString(md5sum); err != nil { + } else if bytes.Compare(b, attrs.MD5) != 0 { + object.Delete(l.ctx) + return ObjectInfo{}, traceError(SignatureDoesNotMatch{}) } return fromGCSObjectInfo(attrs), nil diff --git a/cmd/gateway-handlers.go b/cmd/gateway-handlers.go index c822cea68..fa6af325c 100644 --- a/cmd/gateway-handlers.go +++ b/cmd/gateway-handlers.go @@ -238,8 +238,6 @@ func (api gatewayAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Re // Make sure we hex encode md5sum here. metadata["etag"] = hex.EncodeToString(md5Bytes) - sha256sum := "" - // Lock the object. objectLock := globalNSMutex.NewNSLock(bucket, object) objectLock.Lock() @@ -249,7 +247,7 @@ func (api gatewayAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Re switch reqAuthType { case authTypeAnonymous: // Create anonymous object. - objInfo, err = objectAPI.AnonPutObject(bucket, object, size, r.Body, metadata, sha256sum) + objInfo, err = objectAPI.AnonPutObject(bucket, object, size, r.Body, metadata, "") case authTypeStreamingSigned: // Initialize stream signature verifier. reader, s3Error := newSignV4ChunkedReader(r) @@ -258,7 +256,7 @@ func (api gatewayAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Re writeErrorResponse(w, s3Error, r.URL) return } - objInfo, err = objectAPI.PutObject(bucket, object, size, reader, metadata, sha256sum) + objInfo, err = objectAPI.PutObject(bucket, object, size, reader, metadata, "") case authTypeSignedV2, authTypePresignedV2: s3Error := isReqAuthenticatedV2(r) if s3Error != ErrNone { @@ -266,16 +264,20 @@ func (api gatewayAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Re writeErrorResponse(w, s3Error, r.URL) return } - objInfo, err = objectAPI.PutObject(bucket, object, size, r.Body, metadata, sha256sum) + objInfo, err = objectAPI.PutObject(bucket, object, size, r.Body, metadata, "") case authTypePresigned, authTypeSigned: if s3Error := reqSignatureV4Verify(r, serverConfig.GetRegion()); s3Error != ErrNone { errorIf(errSignatureMismatch, "%s", dumpRequest(r)) writeErrorResponse(w, s3Error, r.URL) return } + + sha256sum := getContentSha256Cksum(r) + if !skipContentSha256Cksum(r) { sha256sum = r.Header.Get("X-Amz-Content-Sha256") } + // Create object. objInfo, err = objectAPI.PutObject(bucket, object, size, r.Body, metadata, sha256sum) default: diff --git a/cmd/object-api-errors.go b/cmd/object-api-errors.go index 5f866db4d..e4ab37cda 100644 --- a/cmd/object-api-errors.go +++ b/cmd/object-api-errors.go @@ -110,6 +110,13 @@ func (e SHA256Mismatch) Error() string { return "sha256 computed does not match with what is expected" } +// SignatureDoesNotMatch - when content md5 does not match with what was sent from client. +type SignatureDoesNotMatch struct{} + +func (e SignatureDoesNotMatch) Error() string { + return "The request signature we calculated does not match the signature you provided. Check your key and signing method." +} + // StorageFull storage ran out of space. type StorageFull struct{}