@ -1635,17 +1635,33 @@ func (s3a *S3ApiServer) copyMultipartCrossEncryption(entry *filer_pb.Entry, r *h
glog . Errorf ( "Failed to serialize SSE-KMS metadata: %v" , serErr )
}
} else if state . DstSSES3 && destSSES3Key != nil {
// For SSE-S3 destination, create object-level metadata using first chunk's IV
// Fail explicitly if metadata is missing to prevent creating unreadable objects
if len ( dstChunks ) == 0 || dstChunks [ 0 ] . GetSseType ( ) != filer_pb . SSEType_SSE_S3 || len ( dstChunks [ 0 ] . GetSseMetadata ( ) ) == 0 {
return nil , nil , fmt . Errorf ( "internal error: first chunk is missing expected SSE-S3 metadata for destination object" )
}
keyManager := GetSSES3KeyManager ( )
sses3Metadata , err := DeserializeSSES3Metadata ( dstChunks [ 0 ] . GetSseMetadata ( ) , keyManager )
if err != nil {
return nil , nil , fmt . Errorf ( "failed to deserialize SSE-S3 metadata from first chunk: %w" , err )
// For SSE-S3 destination, create object-level metadata
var sses3Metadata * SSES3Key
if len ( dstChunks ) == 0 {
// Handle 0-byte files - generate IV for metadata even though there's no content to encrypt
if entry . Attributes . FileSize != 0 {
return nil , nil , fmt . Errorf ( "internal error: no chunks created for non-empty SSE-S3 destination object" )
}
// Generate IV for 0-byte object metadata
iv := make ( [ ] byte , s3_constants . AESBlockSize )
if _ , err := io . ReadFull ( rand . Reader , iv ) ; err != nil {
return nil , nil , fmt . Errorf ( "generate IV for 0-byte object: %w" , err )
}
destSSES3Key . IV = iv
sses3Metadata = destSSES3Key
} else {
// For non-empty objects, use the first chunk's metadata
if dstChunks [ 0 ] . GetSseType ( ) != filer_pb . SSEType_SSE_S3 || len ( dstChunks [ 0 ] . GetSseMetadata ( ) ) == 0 {
return nil , nil , fmt . Errorf ( "internal error: first chunk is missing expected SSE-S3 metadata for destination object" )
}
keyManager := GetSSES3KeyManager ( )
var err error
sses3Metadata , err = DeserializeSSES3Metadata ( dstChunks [ 0 ] . GetSseMetadata ( ) , keyManager )
if err != nil {
return nil , nil , fmt . Errorf ( "failed to deserialize SSE-S3 metadata from first chunk: %w" , err )
}
}
// Use the first chunk's key with its IV for object-level metadata
// Use the derived key with its IV for object-level metadata
keyData , serErr := SerializeSSES3Metadata ( sses3Metadata )
if serErr != nil {
return nil , nil , fmt . Errorf ( "failed to serialize SSE-S3 metadata: %w" , serErr )