SSE-C: Add support in Bucket Post Policy (#5607)

* SSE-C: Add support in Bucket Post Policy

* Rename isSSECustomerRequest & isSSECopyCustomerRequest to hasSSECustomerHeader hasSSECopyCustomerHeader
master
Anis Elleuch 7 years ago committed by kannappanr
parent ea8973b7d7
commit cac10bcbf7
  1. 23
      cmd/bucket-handlers.go
  2. 23
      cmd/encryption-v1.go
  3. 18
      cmd/encryption-v1_test.go
  4. 18
      cmd/object-handlers.go

@ -566,6 +566,29 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
return return
} }
if objectAPI.IsEncryptionSupported() {
if hasSSECustomerHeader(formValues) && !hasSuffix(object, slashSeparator) { // handle SSE-C requests
var reader io.Reader
var key []byte
key, err = ParseSSECustomerHeader(formValues)
if err != nil {
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
return
}
reader, err = newEncryptReader(hashReader, key, metadata)
if err != nil {
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
return
}
info := ObjectInfo{Size: fileSize}
hashReader, err = hash.NewReader(reader, info.EncryptedSize(), "", "") // do not try to verify encrypted content
if err != nil {
writeErrorResponse(w, toAPIErrorCode(err), r.URL)
return
}
}
}
objInfo, err := objectAPI.PutObject(bucket, object, hashReader, metadata) objInfo, err := objectAPI.PutObject(bucket, object, hashReader, metadata)
if err != nil { if err != nil {
writeErrorResponse(w, toAPIErrorCode(err), r.URL) writeErrorResponse(w, toAPIErrorCode(err), r.URL)

@ -144,15 +144,15 @@ const (
// hash function. // hash function.
const SSESealAlgorithmDareSha256 = "DARE-SHA256" const SSESealAlgorithmDareSha256 = "DARE-SHA256"
// IsSSECustomerRequest returns true if the given HTTP header // hasSSECustomerHeader returns true if the given HTTP header
// contains server-side-encryption with customer provided key fields. // contains server-side-encryption with customer provided key fields.
func IsSSECustomerRequest(header http.Header) bool { func hasSSECustomerHeader(header http.Header) bool {
return header.Get(SSECustomerAlgorithm) != "" || header.Get(SSECustomerKey) != "" || header.Get(SSECustomerKeyMD5) != "" return header.Get(SSECustomerAlgorithm) != "" || header.Get(SSECustomerKey) != "" || header.Get(SSECustomerKeyMD5) != ""
} }
// IsSSECopyCustomerRequest returns true if the given HTTP header // hasSSECopyCustomerHeader returns true if the given HTTP header
// contains copy source server-side-encryption with customer provided key fields. // contains copy source server-side-encryption with customer provided key fields.
func IsSSECopyCustomerRequest(header http.Header) bool { func hasSSECopyCustomerHeader(header http.Header) bool {
return header.Get(SSECopyCustomerAlgorithm) != "" || header.Get(SSECopyCustomerKey) != "" || header.Get(SSECopyCustomerKeyMD5) != "" return header.Get(SSECopyCustomerAlgorithm) != "" || header.Get(SSECopyCustomerKey) != "" || header.Get(SSECopyCustomerKeyMD5) != ""
} }
@ -201,6 +201,12 @@ func ParseSSECopyCustomerRequest(r *http.Request) (key []byte, err error) {
// ParseSSECustomerRequest parses the SSE-C header fields of the provided request. // ParseSSECustomerRequest parses the SSE-C header fields of the provided request.
// It returns the client provided key on success. // It returns the client provided key on success.
func ParseSSECustomerRequest(r *http.Request) (key []byte, err error) { func ParseSSECustomerRequest(r *http.Request) (key []byte, err error) {
return ParseSSECustomerHeader(r.Header)
}
// ParseSSECustomerHeader parses the SSE-C header fields and returns
// the client provided key on success.
func ParseSSECustomerHeader(header http.Header) (key []byte, err error) {
if !globalIsSSL { // minio only supports HTTP or HTTPS requests not both at the same time if !globalIsSSL { // minio only supports HTTP or HTTPS requests not both at the same time
// we cannot use r.TLS == nil here because Go's http implementation reflects on // we cannot use r.TLS == nil here because Go's http implementation reflects on
// the net.Conn and sets the TLS field of http.Request only if it's an tls.Conn. // the net.Conn and sets the TLS field of http.Request only if it's an tls.Conn.
@ -208,7 +214,6 @@ func ParseSSECustomerRequest(r *http.Request) (key []byte, err error) {
// will always fail -> r.TLS is always nil even for TLS requests. // will always fail -> r.TLS is always nil even for TLS requests.
return nil, errInsecureSSERequest return nil, errInsecureSSERequest
} }
header := r.Header
if algorithm := header.Get(SSECustomerAlgorithm); algorithm != SSECustomerAlgorithmAES256 { if algorithm := header.Get(SSECustomerAlgorithm); algorithm != SSECustomerAlgorithmAES256 {
return nil, errInvalidSSEAlgorithm return nil, errInvalidSSEAlgorithm
} }
@ -778,10 +783,10 @@ func DecryptCopyObjectInfo(info *ObjectInfo, headers http.Header) (apiErr APIErr
if info.IsDir { if info.IsDir {
return ErrNone, false return ErrNone, false
} }
if apiErr, encrypted = ErrNone, info.IsEncrypted(); !encrypted && IsSSECopyCustomerRequest(headers) { if apiErr, encrypted = ErrNone, info.IsEncrypted(); !encrypted && hasSSECopyCustomerHeader(headers) {
apiErr = ErrInvalidEncryptionParameters apiErr = ErrInvalidEncryptionParameters
} else if encrypted { } else if encrypted {
if !IsSSECopyCustomerRequest(headers) { if !hasSSECopyCustomerHeader(headers) {
apiErr = ErrSSEEncryptedObject apiErr = ErrSSEEncryptedObject
return return
} }
@ -805,10 +810,10 @@ func DecryptObjectInfo(info *ObjectInfo, headers http.Header) (apiErr APIErrorCo
if info.IsDir { if info.IsDir {
return ErrNone, false return ErrNone, false
} }
if apiErr, encrypted = ErrNone, info.IsEncrypted(); !encrypted && IsSSECustomerRequest(headers) { if apiErr, encrypted = ErrNone, info.IsEncrypted(); !encrypted && hasSSECustomerHeader(headers) {
apiErr = ErrInvalidEncryptionParameters apiErr = ErrInvalidEncryptionParameters
} else if encrypted { } else if encrypted {
if !IsSSECustomerRequest(headers) { if !hasSSECustomerHeader(headers) {
apiErr = ErrSSEEncryptedObject apiErr = ErrSSEEncryptedObject
return return
} }

@ -22,7 +22,7 @@ import (
"testing" "testing"
) )
var isSSECopyCustomerRequestTests = []struct { var hasSSECopyCustomerHeaderTests = []struct {
headers map[string]string headers map[string]string
sseRequest bool sseRequest bool
}{ }{
@ -36,18 +36,18 @@ var isSSECopyCustomerRequestTests = []struct {
} }
func TestIsSSECopyCustomerRequest(t *testing.T) { func TestIsSSECopyCustomerRequest(t *testing.T) {
for i, test := range isSSECopyCustomerRequestTests { for i, test := range hasSSECopyCustomerHeaderTests {
headers := http.Header{} headers := http.Header{}
for k, v := range test.headers { for k, v := range test.headers {
headers.Set(k, v) headers.Set(k, v)
} }
if IsSSECopyCustomerRequest(headers) != test.sseRequest { if hasSSECopyCustomerHeader(headers) != test.sseRequest {
t.Errorf("Test %d: Expected IsSSECopyCustomerRequest to return %v", i, test.sseRequest) t.Errorf("Test %d: Expected hasSSECopyCustomerHeader to return %v", i, test.sseRequest)
} }
} }
} }
var isSSECustomerRequestTests = []struct { var hasSSECustomerHeaderTests = []struct {
headers map[string]string headers map[string]string
sseRequest bool sseRequest bool
}{ }{
@ -60,14 +60,14 @@ var isSSECustomerRequestTests = []struct {
{headers: map[string]string{SSECustomerAlgorithm: "", SSECustomerKey: "", SSECustomerKeyMD5: ""}, sseRequest: false}, // 6 {headers: map[string]string{SSECustomerAlgorithm: "", SSECustomerKey: "", SSECustomerKeyMD5: ""}, sseRequest: false}, // 6
} }
func TestIsSSECustomerRequest(t *testing.T) { func TesthasSSECustomerHeader(t *testing.T) {
for i, test := range isSSECustomerRequestTests { for i, test := range hasSSECustomerHeaderTests {
headers := http.Header{} headers := http.Header{}
for k, v := range test.headers { for k, v := range test.headers {
headers.Set(k, v) headers.Set(k, v)
} }
if IsSSECustomerRequest(headers) != test.sseRequest { if hasSSECustomerHeader(headers) != test.sseRequest {
t.Errorf("Test %d: Expected IsSSECustomerRequest to return %v", i, test.sseRequest) t.Errorf("Test %d: Expected hasSSECustomerHeader to return %v", i, test.sseRequest)
} }
} }
} }

@ -147,7 +147,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
var writer io.Writer var writer io.Writer
writer = w writer = w
if objectAPI.IsEncryptionSupported() { if objectAPI.IsEncryptionSupported() {
if IsSSECustomerRequest(r.Header) { if hasSSECustomerHeader(r.Header) {
// Response writer should be limited early on for decryption upto required length, // Response writer should be limited early on for decryption upto required length,
// additionally also skipping mod(offset)64KiB boundaries. // additionally also skipping mod(offset)64KiB boundaries.
writer = ioutil.LimitedWriter(writer, startOffset%(64*1024), length) writer = ioutil.LimitedWriter(writer, startOffset%(64*1024), length)
@ -397,8 +397,8 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
var encMetadata = make(map[string]string) var encMetadata = make(map[string]string)
if objectAPI.IsEncryptionSupported() { if objectAPI.IsEncryptionSupported() {
var oldKey, newKey []byte var oldKey, newKey []byte
sseCopyC := IsSSECopyCustomerRequest(r.Header) sseCopyC := hasSSECopyCustomerHeader(r.Header)
sseC := IsSSECustomerRequest(r.Header) sseC := hasSSECustomerHeader(r.Header)
if sseC { if sseC {
newKey, err = ParseSSECustomerRequest(r) newKey, err = ParseSSECustomerRequest(r)
if err != nil { if err != nil {
@ -668,7 +668,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
} }
if objectAPI.IsEncryptionSupported() { if objectAPI.IsEncryptionSupported() {
if IsSSECustomerRequest(r.Header) && !hasSuffix(object, slashSeparator) { // handle SSE-C requests if hasSSECustomerHeader(r.Header) && !hasSuffix(object, slashSeparator) { // handle SSE-C requests
reader, err = EncryptRequest(hashReader, r, metadata) reader, err = EncryptRequest(hashReader, r, metadata)
if err != nil { if err != nil {
writeErrorResponse(w, toAPIErrorCode(err), r.URL) writeErrorResponse(w, toAPIErrorCode(err), r.URL)
@ -691,7 +691,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req
w.Header().Set("ETag", "\""+objInfo.ETag+"\"") w.Header().Set("ETag", "\""+objInfo.ETag+"\"")
if objectAPI.IsEncryptionSupported() { if objectAPI.IsEncryptionSupported() {
if IsSSECustomerRequest(r.Header) { if hasSSECustomerHeader(r.Header) {
w.Header().Set(SSECustomerAlgorithm, r.Header.Get(SSECustomerAlgorithm)) w.Header().Set(SSECustomerAlgorithm, r.Header.Get(SSECustomerAlgorithm))
w.Header().Set(SSECustomerKeyMD5, r.Header.Get(SSECustomerKeyMD5)) w.Header().Set(SSECustomerKeyMD5, r.Header.Get(SSECustomerKeyMD5))
} }
@ -748,7 +748,7 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r
var encMetadata = map[string]string{} var encMetadata = map[string]string{}
if objectAPI.IsEncryptionSupported() { if objectAPI.IsEncryptionSupported() {
if IsSSECustomerRequest(r.Header) { if hasSSECustomerHeader(r.Header) {
key, err := ParseSSECustomerRequest(r) key, err := ParseSSECustomerRequest(r)
if err != nil { if err != nil {
writeErrorResponse(w, toAPIErrorCode(err), r.URL) writeErrorResponse(w, toAPIErrorCode(err), r.URL)
@ -903,7 +903,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
writeErrorResponse(w, toAPIErrorCode(err), r.URL) writeErrorResponse(w, toAPIErrorCode(err), r.URL)
return return
} }
sseCopyC := IsSSECopyCustomerRequest(r.Header) sseCopyC := hasSSECopyCustomerHeader(r.Header)
if sseCopyC { if sseCopyC {
// Response writer should be limited early on for decryption upto required length, // Response writer should be limited early on for decryption upto required length,
// additionally also skipping mod(offset)64KiB boundaries. // additionally also skipping mod(offset)64KiB boundaries.
@ -916,7 +916,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt
} }
} }
if li.IsEncrypted() { if li.IsEncrypted() {
if !IsSSECustomerRequest(r.Header) { if !hasSSECustomerHeader(r.Header) {
writeErrorResponse(w, ErrSSEMultipartEncrypted, r.URL) writeErrorResponse(w, ErrSSEMultipartEncrypted, r.URL)
return return
} }
@ -1105,7 +1105,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
return return
} }
if li.IsEncrypted() { if li.IsEncrypted() {
if !IsSSECustomerRequest(r.Header) { if !hasSSECustomerHeader(r.Header) {
writeErrorResponse(w, ErrSSEMultipartEncrypted, r.URL) writeErrorResponse(w, ErrSSEMultipartEncrypted, r.URL)
return return
} }

Loading…
Cancel
Save