test(e2e): require exact SSE-C errors (#6546)

This commit is contained in:
Zhengchao An
2026-08-25 04:32:30 +08:00
committed by GitHub
parent 116119d93a
commit 40e6decc93
6 changed files with 154 additions and 41 deletions
+66 -15
View File
@@ -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?;