mirror of https://github.com/minio/minio.git
				
				
				
			return AWS S3 compatible error for invalid but equal keys during key rotation (#5783)
This change let the server return the S3 error for a key rotation if the source key is not valid but equal to the destination key. This change also fixes the SSE-C error messages since AWS returns error messages ending with a '.'. Fixes #5625
This commit is contained in:
		
							parent
							
								
									73f7a98590
								
							
						
					
					
						commit
						da9f0e324e
					
				|  | @ -138,6 +138,7 @@ const ( | ||||||
| 	ErrMissingSSECustomerKey | 	ErrMissingSSECustomerKey | ||||||
| 	ErrMissingSSECustomerKeyMD5 | 	ErrMissingSSECustomerKeyMD5 | ||||||
| 	ErrSSECustomerKeyMD5Mismatch | 	ErrSSECustomerKeyMD5Mismatch | ||||||
|  | 	ErrInvalidSSECustomerParameters | ||||||
| 
 | 
 | ||||||
| 	// Bucket notification related errors.
 | 	// Bucket notification related errors.
 | ||||||
| 	ErrEventNotification | 	ErrEventNotification | ||||||
|  | @ -629,7 +630,7 @@ var errorCodeResponse = map[APIErrorCode]APIError{ | ||||||
| 	}, | 	}, | ||||||
| 	ErrInsecureSSECustomerRequest: { | 	ErrInsecureSSECustomerRequest: { | ||||||
| 		Code:           "InvalidRequest", | 		Code:           "InvalidRequest", | ||||||
| 		Description:    errInsecureSSERequest.Error(), | 		Description:    "Requests specifying Server Side Encryption with Customer provided keys must be made over a secure connection.", | ||||||
| 		HTTPStatusCode: http.StatusBadRequest, | 		HTTPStatusCode: http.StatusBadRequest, | ||||||
| 	}, | 	}, | ||||||
| 	ErrSSEMultipartEncrypted: { | 	ErrSSEMultipartEncrypted: { | ||||||
|  | @ -639,7 +640,7 @@ var errorCodeResponse = map[APIErrorCode]APIError{ | ||||||
| 	}, | 	}, | ||||||
| 	ErrSSEEncryptedObject: { | 	ErrSSEEncryptedObject: { | ||||||
| 		Code:           "InvalidRequest", | 		Code:           "InvalidRequest", | ||||||
| 		Description:    errEncryptedObject.Error(), | 		Description:    "The object was stored using a form of Server Side Encryption. The correct parameters must be provided to retrieve the object.", | ||||||
| 		HTTPStatusCode: http.StatusBadRequest, | 		HTTPStatusCode: http.StatusBadRequest, | ||||||
| 	}, | 	}, | ||||||
| 	ErrInvalidEncryptionParameters: { | 	ErrInvalidEncryptionParameters: { | ||||||
|  | @ -649,27 +650,32 @@ var errorCodeResponse = map[APIErrorCode]APIError{ | ||||||
| 	}, | 	}, | ||||||
| 	ErrInvalidSSECustomerAlgorithm: { | 	ErrInvalidSSECustomerAlgorithm: { | ||||||
| 		Code:           "InvalidArgument", | 		Code:           "InvalidArgument", | ||||||
| 		Description:    errInvalidSSEAlgorithm.Error(), | 		Description:    "Requests specifying Server Side Encryption with Customer provided keys must provide a valid encryption algorithm.", | ||||||
| 		HTTPStatusCode: http.StatusBadRequest, | 		HTTPStatusCode: http.StatusBadRequest, | ||||||
| 	}, | 	}, | ||||||
| 	ErrInvalidSSECustomerKey: { | 	ErrInvalidSSECustomerKey: { | ||||||
| 		Code:           "InvalidArgument", | 		Code:           "InvalidArgument", | ||||||
| 		Description:    errInvalidSSEKey.Error(), | 		Description:    "The secret key was invalid for the specified algorithm.", | ||||||
| 		HTTPStatusCode: http.StatusBadRequest, | 		HTTPStatusCode: http.StatusBadRequest, | ||||||
| 	}, | 	}, | ||||||
| 	ErrMissingSSECustomerKey: { | 	ErrMissingSSECustomerKey: { | ||||||
| 		Code:           "InvalidArgument", | 		Code:           "InvalidArgument", | ||||||
| 		Description:    errMissingSSEKey.Error(), | 		Description:    "Requests specifying Server Side Encryption with Customer provided keys must provide an appropriate secret key.", | ||||||
| 		HTTPStatusCode: http.StatusBadRequest, | 		HTTPStatusCode: http.StatusBadRequest, | ||||||
| 	}, | 	}, | ||||||
| 	ErrMissingSSECustomerKeyMD5: { | 	ErrMissingSSECustomerKeyMD5: { | ||||||
| 		Code:           "InvalidArgument", | 		Code:           "InvalidArgument", | ||||||
| 		Description:    errMissingSSEKeyMD5.Error(), | 		Description:    "Requests specifying Server Side Encryption with Customer provided keys must provide the client calculated MD5 of the secret key.", | ||||||
| 		HTTPStatusCode: http.StatusBadRequest, | 		HTTPStatusCode: http.StatusBadRequest, | ||||||
| 	}, | 	}, | ||||||
| 	ErrSSECustomerKeyMD5Mismatch: { | 	ErrSSECustomerKeyMD5Mismatch: { | ||||||
| 		Code:           "InvalidArgument", | 		Code:           "InvalidArgument", | ||||||
| 		Description:    errSSEKeyMD5Mismatch.Error(), | 		Description:    "The calculated MD5 hash of the key did not match the hash that was provided.", | ||||||
|  | 		HTTPStatusCode: http.StatusBadRequest, | ||||||
|  | 	}, | ||||||
|  | 	ErrInvalidSSECustomerParameters: { | ||||||
|  | 		Code:           "InvalidArgument", | ||||||
|  | 		Description:    "The provided encryption parameters did not match the ones used originally.", | ||||||
| 		HTTPStatusCode: http.StatusBadRequest, | 		HTTPStatusCode: http.StatusBadRequest, | ||||||
| 	}, | 	}, | ||||||
| 
 | 
 | ||||||
|  | @ -884,6 +890,8 @@ func toAPIErrorCode(err error) (apiErr APIErrorCode) { | ||||||
| 		return ErrObjectTampered | 		return ErrObjectTampered | ||||||
| 	case errEncryptedObject: | 	case errEncryptedObject: | ||||||
| 		return ErrSSEEncryptedObject | 		return ErrSSEEncryptedObject | ||||||
|  | 	case errInvalidSSEParameters: | ||||||
|  | 		return ErrInvalidSSECustomerParameters | ||||||
| 	case errSSEKeyMismatch: | 	case errSSEKeyMismatch: | ||||||
| 		return ErrAccessDenied // no access without correct key
 | 		return ErrAccessDenied // no access without correct key
 | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -35,14 +35,15 @@ import ( | ||||||
| 
 | 
 | ||||||
| var ( | var ( | ||||||
| 	// AWS errors for invalid SSE-C requests.
 | 	// AWS errors for invalid SSE-C requests.
 | ||||||
| 	errInsecureSSERequest  = errors.New("Requests specifying Server Side Encryption with Customer provided keys must be made over a secure connection") | 	errInsecureSSERequest   = errors.New("SSE-C requests require TLS connections") | ||||||
| 	errEncryptedObject     = errors.New("The object was stored using a form of Server Side Encryption. The correct parameters must be provided to retrieve the object") | 	errEncryptedObject      = errors.New("The object was stored using a form of SSE") | ||||||
| 	errInvalidSSEAlgorithm = errors.New("Requests specifying Server Side Encryption with Customer provided keys must provide a valid encryption algorithm") | 	errInvalidSSEAlgorithm  = errors.New("The SSE-C algorithm is not valid") | ||||||
| 	errMissingSSEKey       = errors.New("Requests specifying Server Side Encryption with Customer provided keys must provide an appropriate secret key") | 	errMissingSSEKey        = errors.New("The SSE-C request is missing the customer key") | ||||||
| 	errInvalidSSEKey       = errors.New("The secret key was invalid for the specified algorithm") | 	errInvalidSSEKey        = errors.New("The SSE-C key is invalid") | ||||||
| 	errMissingSSEKeyMD5    = errors.New("Requests specifying Server Side Encryption with Customer provided keys must provide the client calculated MD5 of the secret key") | 	errMissingSSEKeyMD5     = errors.New("The SSE-C request is missing the customer key MD5") | ||||||
| 	errSSEKeyMD5Mismatch   = errors.New("The calculated MD5 hash of the key did not match the hash that was provided") | 	errSSEKeyMD5Mismatch    = errors.New("The key MD5 does not match the SSE-C key") | ||||||
| 	errSSEKeyMismatch      = errors.New("The client provided key does not match the key provided when the object was encrypted") // this msg is not shown to the client
 | 	errSSEKeyMismatch       = errors.New("The SSE-C key is not correct")                  // access denied
 | ||||||
|  | 	errInvalidSSEParameters = errors.New("The SSE-C key for key-rotation is not correct") // special access denied
 | ||||||
| 
 | 
 | ||||||
| 	// Additional Minio errors for SSE-C requests.
 | 	// Additional Minio errors for SSE-C requests.
 | ||||||
| 	errObjectTampered = errors.New("The requested object was modified and may be compromised") | 	errObjectTampered = errors.New("The requested object was modified and may be compromised") | ||||||
|  | @ -247,9 +248,6 @@ func ParseSSECustomerHeader(header http.Header) (key []byte, err error) { | ||||||
| 
 | 
 | ||||||
| // This function rotates old to new key.
 | // This function rotates old to new key.
 | ||||||
| func rotateKey(oldKey []byte, newKey []byte, metadata map[string]string) error { | func rotateKey(oldKey []byte, newKey []byte, metadata map[string]string) error { | ||||||
| 	if subtle.ConstantTimeCompare(oldKey, newKey) == 1 { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	delete(metadata, SSECustomerKey) // make sure we do not save the key by accident
 | 	delete(metadata, SSECustomerKey) // make sure we do not save the key by accident
 | ||||||
| 
 | 
 | ||||||
| 	if metadata[ServerSideEncryptionSealAlgorithm] != SSESealAlgorithmDareSha256 { // currently DARE-SHA256 is the only option
 | 	if metadata[ServerSideEncryptionSealAlgorithm] != SSESealAlgorithmDareSha256 { // currently DARE-SHA256 is the only option
 | ||||||
|  | @ -273,10 +271,14 @@ func rotateKey(oldKey []byte, newKey []byte, metadata map[string]string) error { | ||||||
| 	n, err := sio.Decrypt(objectEncryptionKey, bytes.NewReader(sealedKey), sio.Config{ | 	n, err := sio.Decrypt(objectEncryptionKey, bytes.NewReader(sealedKey), sio.Config{ | ||||||
| 		Key: keyEncryptionKey, | 		Key: keyEncryptionKey, | ||||||
| 	}) | 	}) | ||||||
| 	if n != 32 || err != nil { | 	if n != 32 || err != nil { // Either the provided key does not match or the object was tampered.
 | ||||||
| 		// Either the provided key does not match or the object was tampered.
 | 		if subtle.ConstantTimeCompare(oldKey, newKey) == 1 { | ||||||
| 		// To provide strict AWS S3 compatibility we return: access denied.
 | 			return errInvalidSSEParameters // AWS returns special error for equal but invalid keys.
 | ||||||
| 		return errSSEKeyMismatch | 		} | ||||||
|  | 		return errSSEKeyMismatch // To provide strict AWS S3 compatibility we return: access denied.
 | ||||||
|  | 	} | ||||||
|  | 	if subtle.ConstantTimeCompare(oldKey, newKey) == 1 { | ||||||
|  | 		return nil // we don't need to rotate keys if newKey == oldKey
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	nonce := make([]byte, 32) // generate random values for key derivation
 | 	nonce := make([]byte, 32) // generate random values for key derivation
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue