@ -17,6 +17,7 @@ package crypto
import (
import (
"context"
"context"
"encoding/base64"
"encoding/base64"
"errors"
"fmt"
"fmt"
"github.com/minio/minio/cmd/logger"
"github.com/minio/minio/cmd/logger"
@ -119,28 +120,46 @@ func CreateMultipartMetadata(metadata map[string]string) map[string]string {
return metadata
return metadata
}
}
// CreateMetadata encodes the keyID, the sealed kms data key and the sealed key
// CreateMetadata encodes the sealed object key into the metadata and returns
// into the metadata and returns the modified metadata. It allocates a new
// the modified metadata. If the keyID and the kmsKey is not empty it encodes
// metadata map if metadata is nil.
// both into the metadata as well. It allocates a new metadata map if metadata
// is nil.
func ( s3 ) CreateMetadata ( metadata map [ string ] string , keyID string , kmsKey [ ] byte , sealedKey SealedKey ) map [ string ] string {
func ( s3 ) CreateMetadata ( metadata map [ string ] string , keyID string , kmsKey [ ] byte , sealedKey SealedKey ) map [ string ] string {
if sealedKey . Algorithm != SealAlgorithm {
if sealedKey . Algorithm != SealAlgorithm {
logger . CriticalIf ( context . Background ( ) , fmt . Errorf ( "The seal algorithm '%s' is invalid for SSE-S3" , sealedKey . Algorithm ) )
logger . CriticalIf ( context . Background ( ) , fmt . Errorf ( "The seal algorithm '%s' is invalid for SSE-S3" , sealedKey . Algorithm ) )
}
}
// There are two possibilites:
// - We use a KMS -> There must be non-empty key ID and a KMS data key.
// - We use a K/V -> There must be no key ID and no KMS data key.
// Otherwise, the caller has passed an invalid argument combination.
if keyID == "" && len ( kmsKey ) != 0 {
logger . CriticalIf ( context . Background ( ) , errors . New ( "The key ID must not be empty if a KMS data key is present" ) )
}
if keyID != "" && len ( kmsKey ) == 0 {
logger . CriticalIf ( context . Background ( ) , errors . New ( "The KMS data key must not be empty if a key ID is present" ) )
}
if metadata == nil {
if metadata == nil {
metadata = map [ string ] string { }
metadata = map [ string ] string { }
}
}
metadata [ S3KMSKeyID ] = keyID
metadata [ SSESealAlgorithm ] = sealedKey . Algorithm
metadata [ SSESealAlgorithm ] = sealedKey . Algorithm
metadata [ SSEIV ] = base64 . StdEncoding . EncodeToString ( sealedKey . IV [ : ] )
metadata [ SSEIV ] = base64 . StdEncoding . EncodeToString ( sealedKey . IV [ : ] )
metadata [ S3SealedKey ] = base64 . StdEncoding . EncodeToString ( sealedKey . Key [ : ] )
metadata [ S3SealedKey ] = base64 . StdEncoding . EncodeToString ( sealedKey . Key [ : ] )
if len ( kmsKey ) > 0 && keyID != "" { // We use a KMS -> Store key ID and sealed KMS data key.
metadata [ S3KMSKeyID ] = keyID
metadata [ S3KMSSealedKey ] = base64 . StdEncoding . EncodeToString ( kmsKey )
metadata [ S3KMSSealedKey ] = base64 . StdEncoding . EncodeToString ( kmsKey )
}
return metadata
return metadata
}
}
// ParseMetadata extracts all SSE-S3 related values from the object metadata
// ParseMetadata extracts all SSE-S3 related values from the object metadata
// and checks whether they are well-formed. It returns the KMS key-ID, the
// and checks whether they are well-formed. It returns the sealed object key
// sealed KMS key and the sealed object key on success.
// on success. If the metadata contains both, a KMS master key ID and a sealed
// KMS data key it returns both. If the metadata does not contain neither a
// KMS master key ID nor a sealed KMS data key it returns an empty keyID and
// KMS data key. Otherwise, it returns an error.
func ( s3 ) ParseMetadata ( metadata map [ string ] string ) ( keyID string , kmsKey [ ] byte , sealedKey SealedKey , err error ) {
func ( s3 ) ParseMetadata ( metadata map [ string ] string ) ( keyID string , kmsKey [ ] byte , sealedKey SealedKey , err error ) {
// Extract all required values from object metadata
// Extract all required values from object metadata
b64IV , ok := metadata [ SSEIV ]
b64IV , ok := metadata [ SSEIV ]
@ -155,12 +174,17 @@ func (s3) ParseMetadata(metadata map[string]string) (keyID string, kmsKey []byte
if ! ok {
if ! ok {
return keyID , kmsKey , sealedKey , Error { "The object metadata is missing the internal sealed key for SSE-S3" }
return keyID , kmsKey , sealedKey , Error { "The object metadata is missing the internal sealed key for SSE-S3" }
}
}
keyID , ok = metadata [ S3KMSKeyID ]
if ! ok {
// There are two possibilites:
// - We use a KMS -> There must be a key ID and a KMS data key.
// - We use a K/V -> There must be no key ID and no KMS data key.
// Otherwise, the metadata is corrupted.
keyID , idPresent := metadata [ S3KMSKeyID ]
b64KMSSealedKey , kmsKeyPresent := metadata [ S3KMSSealedKey ]
if ! idPresent && kmsKeyPresent {
return keyID , kmsKey , sealedKey , Error { "The object metadata is missing the internal KMS key-ID for SSE-S3" }
return keyID , kmsKey , sealedKey , Error { "The object metadata is missing the internal KMS key-ID for SSE-S3" }
}
}
b64KMSSealedKey , ok := metadata [ S3KMSSealedKey ]
if idPresent && ! kmsKeyPresent {
if ! ok {
return keyID , kmsKey , sealedKey , Error { "The object metadata is missing the internal sealed KMS data key for SSE-S3" }
return keyID , kmsKey , sealedKey , Error { "The object metadata is missing the internal sealed KMS data key for SSE-S3" }
}
}
@ -176,10 +200,12 @@ func (s3) ParseMetadata(metadata map[string]string) (keyID string, kmsKey []byte
if err != nil || len ( encryptedKey ) != 64 {
if err != nil || len ( encryptedKey ) != 64 {
return keyID , kmsKey , sealedKey , Error { "The internal sealed key for SSE-S3 is invalid" }
return keyID , kmsKey , sealedKey , Error { "The internal sealed key for SSE-S3 is invalid" }
}
}
if idPresent && kmsKeyPresent { // We are using a KMS -> parse the sealed KMS data key.
kmsKey , err = base64 . StdEncoding . DecodeString ( b64KMSSealedKey )
kmsKey , err = base64 . StdEncoding . DecodeString ( b64KMSSealedKey )
if err != nil {
if err != nil {
return keyID , kmsKey , sealedKey , Error { "The internal sealed KMS data key for SSE-S3 is invalid" }
return keyID , kmsKey , sealedKey , Error { "The internal sealed KMS data key for SSE-S3 is invalid" }
}
}
}
sealedKey . Algorithm = algorithm
sealedKey . Algorithm = algorithm
copy ( sealedKey . IV [ : ] , iv )
copy ( sealedKey . IV [ : ] , iv )