Browse Source

Address review: handle 0-byte files in SSE-S3 copy

For 0-byte files, there are no chunks to get metadata from. Generate an IV
for the object-level metadata to ensure even empty files are properly marked
as SSE-S3 encrypted.

Also validate that we don't have a non-empty file with no chunks (which
would indicate an internal error).
pull/7598/head
chrislu 2 days ago
parent
commit
74c9f5db89
  1. 36
      weed/s3api/s3api_object_handlers_copy.go

36
weed/s3api/s3api_object_handlers_copy.go

@ -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)

Loading…
Cancel
Save