mirror of
https://github.com/rustfs/rustfs.git
synced 2026-09-04 03:05:39 +00:00
test(e2e): require exact SSE-C errors (#6546)
This commit is contained in:
@@ -21,21 +21,14 @@
|
||||
//! - Concurrent encryption operations
|
||||
//! - Security validation tests
|
||||
|
||||
use super::common::{LocalKMSTestEnvironment, sse_customer_key_md5_base64};
|
||||
use super::common::{LocalKMSTestEnvironment, SSE_C_KEY_MISMATCH_MESSAGE, assert_s3_error, sse_customer_key_md5_base64};
|
||||
use crate::common::{TEST_BUCKET, init_logging};
|
||||
use aws_sdk_s3::types::ServerSideEncryption;
|
||||
use base64::Engine;
|
||||
use md5::{Digest as Md5Digest, Md5};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Semaphore;
|
||||
use tracing::{info, warn};
|
||||
|
||||
fn md5_hex(input: impl AsRef<[u8]>) -> String {
|
||||
let mut hasher = Md5::new();
|
||||
hasher.update(input.as_ref());
|
||||
hex::encode(hasher.finalize())
|
||||
}
|
||||
|
||||
/// Test encryption of zero-byte files (empty files)
|
||||
#[tokio::test]
|
||||
async fn test_kms_zero_byte_file_encryption() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
@@ -295,7 +288,7 @@ async fn test_kms_invalid_key_scenarios() -> Result<(), Box<dyn std::error::Erro
|
||||
info!("🔍 Testing invalid SSE-C key length");
|
||||
let invalid_short_key = "short"; // Too short
|
||||
let invalid_key_b64 = base64::engine::general_purpose::STANDARD.encode(invalid_short_key);
|
||||
let invalid_key_md5 = md5_hex(invalid_short_key);
|
||||
let invalid_key_md5 = sse_customer_key_md5_base64(invalid_short_key);
|
||||
|
||||
let invalid_key_result = s3_client
|
||||
.put_object()
|
||||
@@ -308,14 +301,32 @@ async fn test_kms_invalid_key_scenarios() -> Result<(), Box<dyn std::error::Erro
|
||||
.send()
|
||||
.await;
|
||||
|
||||
assert!(invalid_key_result.is_err(), "Should reject invalid key length");
|
||||
assert_s3_error(
|
||||
invalid_key_result,
|
||||
400,
|
||||
"InvalidRequest",
|
||||
"SSE-C key must be 32 bytes (256 bits), got 5 bytes.",
|
||||
"invalid SSE-C key length must be rejected",
|
||||
);
|
||||
assert_s3_error(
|
||||
s3_client
|
||||
.get_object()
|
||||
.bucket(TEST_BUCKET)
|
||||
.key("test-invalid-key-length")
|
||||
.send()
|
||||
.await,
|
||||
404,
|
||||
"NoSuchKey",
|
||||
"The specified key does not exist.",
|
||||
"rejected invalid-key PUT must not create an object",
|
||||
);
|
||||
info!("✅ Correctly rejected invalid key length");
|
||||
|
||||
// Test 2: Mismatched MD5 for SSE-C
|
||||
info!("🔍 Testing mismatched MD5 for SSE-C key");
|
||||
let valid_key = "01234567890123456789012345678901";
|
||||
let valid_key_b64 = base64::engine::general_purpose::STANDARD.encode(valid_key);
|
||||
let wrong_md5 = "wrongmd5hash12345678901234567890"; // Wrong MD5
|
||||
let wrong_md5 = sse_customer_key_md5_base64("98765432109876543210987654321098");
|
||||
|
||||
let wrong_md5_result = s3_client
|
||||
.put_object()
|
||||
@@ -324,11 +335,24 @@ async fn test_kms_invalid_key_scenarios() -> Result<(), Box<dyn std::error::Erro
|
||||
.body(aws_sdk_s3::primitives::ByteStream::from(test_data.to_vec()))
|
||||
.sse_customer_algorithm("AES256")
|
||||
.sse_customer_key(&valid_key_b64)
|
||||
.sse_customer_key_md5(wrong_md5)
|
||||
.sse_customer_key_md5(&wrong_md5)
|
||||
.send()
|
||||
.await;
|
||||
|
||||
assert!(wrong_md5_result.is_err(), "Should reject mismatched MD5");
|
||||
assert_s3_error(
|
||||
wrong_md5_result,
|
||||
400,
|
||||
"InvalidRequest",
|
||||
"The calculated MD5 hash of the key did not match the hash that was provided.",
|
||||
"mismatched SSE-C key MD5 must be rejected",
|
||||
);
|
||||
assert_s3_error(
|
||||
s3_client.get_object().bucket(TEST_BUCKET).key("test-wrong-md5").send().await,
|
||||
404,
|
||||
"NoSuchKey",
|
||||
"The specified key does not exist.",
|
||||
"rejected mismatched-MD5 PUT must not create an object",
|
||||
);
|
||||
info!("✅ Correctly rejected mismatched MD5");
|
||||
|
||||
// Test 3: Try to access SSE-C object without providing key
|
||||
@@ -355,7 +379,28 @@ async fn test_kms_invalid_key_scenarios() -> Result<(), Box<dyn std::error::Erro
|
||||
.send()
|
||||
.await;
|
||||
|
||||
assert!(no_key_result.is_err(), "Should require SSE-C key for access");
|
||||
assert_s3_error(
|
||||
no_key_result,
|
||||
400,
|
||||
"InvalidRequest",
|
||||
"The object was stored using a form of Server Side Encryption. The correct parameters must be provided to retrieve the object.",
|
||||
"SSE-C object GET without a customer key must be rejected",
|
||||
);
|
||||
|
||||
let recovered = s3_client
|
||||
.get_object()
|
||||
.bucket(TEST_BUCKET)
|
||||
.key("test-sse-c-no-key-access")
|
||||
.sse_customer_algorithm("AES256")
|
||||
.sse_customer_key(&valid_key_b64)
|
||||
.sse_customer_key_md5(&valid_key_md5)
|
||||
.send()
|
||||
.await?
|
||||
.body
|
||||
.collect()
|
||||
.await?
|
||||
.into_bytes();
|
||||
assert_eq!(recovered.as_ref(), test_data, "failed GET must not corrupt the SSE-C object");
|
||||
info!("✅ Correctly required SSE-C key for access");
|
||||
|
||||
kms_env.base_env.delete_test_bucket(TEST_BUCKET).await?;
|
||||
@@ -563,7 +608,13 @@ async fn test_kms_key_validation_security() -> Result<(), Box<dyn std::error::Er
|
||||
.send()
|
||||
.await;
|
||||
|
||||
assert!(wrong_key_result.is_err(), "Should not be able to decrypt with wrong key");
|
||||
assert_s3_error(
|
||||
wrong_key_result,
|
||||
400,
|
||||
"InvalidRequest",
|
||||
SSE_C_KEY_MISMATCH_MESSAGE,
|
||||
"SSE-C object GET with the wrong customer key must be rejected",
|
||||
);
|
||||
info!("✅ Key isolation verified - wrong key cannot decrypt data");
|
||||
|
||||
kms_env.base_env.delete_test_bucket(TEST_BUCKET).await?;
|
||||
|
||||
Reference in New Issue
Block a user