286 lines
9.0 KiB
Rust
286 lines
9.0 KiB
Rust
|
|
use std::str::FromStr;
|
||
|
|
|
||
|
|
use vault_service::{
|
||
|
|
service::KmsService,
|
||
|
|
types::{EncryptionContext, KeySpec, KmsBackendConfig},
|
||
|
|
};
|
||
|
|
|
||
|
|
/// Test encryption context
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_encryption_context() {
|
||
|
|
let mut ctx = EncryptionContext::new();
|
||
|
|
ctx.add("environment", "test");
|
||
|
|
ctx.add("service", "integration-test");
|
||
|
|
|
||
|
|
assert_eq!(ctx.context.len(), 2);
|
||
|
|
assert_eq!(ctx.context.get("environment").unwrap(), "test");
|
||
|
|
|
||
|
|
let ctx_str = ctx.to_string();
|
||
|
|
assert!(ctx_str.contains("environment=test"));
|
||
|
|
assert!(ctx_str.contains("service=integration-test"));
|
||
|
|
|
||
|
|
let parsed = EncryptionContext::from_str(&ctx_str).unwrap();
|
||
|
|
assert_eq!(parsed.context.len(), 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Test key spec sizes
|
||
|
|
#[test]
|
||
|
|
fn test_key_spec_sizes() {
|
||
|
|
assert_eq!(KeySpec::Aes128.key_size(), 16);
|
||
|
|
assert_eq!(KeySpec::Aes256.key_size(), 32);
|
||
|
|
assert_eq!(KeySpec::Rsa2048.key_size(), 256);
|
||
|
|
assert_eq!(KeySpec::Rsa4096.key_size(), 512);
|
||
|
|
}
|
||
|
|
|
||
|
|
// /// Test Vault backend initialization (requires Vault running)
|
||
|
|
// #[tokio::test]
|
||
|
|
// #[ignore] // Ignore by default, run with --ignored flag when Vault is
|
||
|
|
// available async fn test_vault_backend_init() {
|
||
|
|
// let config = KmsBackendConfig::Vault {
|
||
|
|
// address: "http://localhost:8200".to_string(),
|
||
|
|
// token: std::env::var("VAULT_TOKEN").expect("VAULT_TOKEN not set"),
|
||
|
|
// mount_point: "transit".to_string(),
|
||
|
|
// namespace: None,
|
||
|
|
// auto_renew_token: false,
|
||
|
|
// };
|
||
|
|
//
|
||
|
|
// let service = KmsService::new(config).await;
|
||
|
|
// assert!(service.is_ok(), "Failed to initialize Vault backend");
|
||
|
|
//
|
||
|
|
// let service = service.unwrap();
|
||
|
|
// assert_eq!(service.get_backend_name(), "vault");
|
||
|
|
// }
|
||
|
|
|
||
|
|
// AWS KMS backend not yet implemented
|
||
|
|
// Test AWS KMS backend initialization (requires AWS credentials)
|
||
|
|
// #[tokio::test]
|
||
|
|
// #[ignore] // Ignore by default, run with --ignored flag when AWS is
|
||
|
|
// configured async fn test_aws_kms_backend_init() {
|
||
|
|
// let key_id = std::env::var("AWS_KMS_KEY_ID").expect("AWS_KMS_KEY_ID not
|
||
|
|
// set");
|
||
|
|
//
|
||
|
|
// let config = KmsBackendConfig::AwsKms {
|
||
|
|
// region: "us-east-1".to_string(),
|
||
|
|
// key_id,
|
||
|
|
// assume_role: None,
|
||
|
|
// };
|
||
|
|
//
|
||
|
|
// let service = KmsService::new(config).await;
|
||
|
|
// assert!(service.is_ok(), "Failed to initialize AWS KMS backend");
|
||
|
|
//
|
||
|
|
// let service = service.unwrap();
|
||
|
|
// assert_eq!(service.get_backend_name(), "aws-kms");
|
||
|
|
// }
|
||
|
|
|
||
|
|
// /// Test encryption and decryption round-trip with Vault
|
||
|
|
// #[tokio::test]
|
||
|
|
// #[ignore] // Requires Vault
|
||
|
|
// async fn test_vault_encrypt_decrypt_roundtrip() {
|
||
|
|
// let config = KmsBackendConfig::Vault {
|
||
|
|
// address: "http://localhost:8200".to_string(),
|
||
|
|
// token: std::env::var("VAULT_TOKEN").expect("VAULT_TOKEN not set"),
|
||
|
|
// mount_point: "transit".to_string(),
|
||
|
|
// namespace: None,
|
||
|
|
// auto_renew_token: false,
|
||
|
|
// };
|
||
|
|
//
|
||
|
|
// let service = KmsService::new(config).await.unwrap();
|
||
|
|
//
|
||
|
|
// let plaintext = b"Hello, Vault KMS!";
|
||
|
|
// let mut context = EncryptionContext::new();
|
||
|
|
// context.add("test", "integration");
|
||
|
|
//
|
||
|
|
// // Encrypt
|
||
|
|
// let ciphertext = service.encrypt(plaintext, &context).await.unwrap();
|
||
|
|
// assert!(!ciphertext.is_empty());
|
||
|
|
// assert_ne!(ciphertext, plaintext);
|
||
|
|
//
|
||
|
|
// // Decrypt
|
||
|
|
// let decrypted = service.decrypt(&ciphertext, &context).await.unwrap();
|
||
|
|
// assert_eq!(decrypted, plaintext);
|
||
|
|
// }
|
||
|
|
//
|
||
|
|
// /// Test encryption and decryption round-trip with AWS KMS
|
||
|
|
// #[tokio::test]
|
||
|
|
// #[ignore] // Requires AWS KMS
|
||
|
|
// async fn test_aws_kms_encrypt_decrypt_roundtrip() {
|
||
|
|
// let key_id = std::env::var("AWS_KMS_KEY_ID").expect("AWS_KMS_KEY_ID not
|
||
|
|
// set");
|
||
|
|
//
|
||
|
|
// let config = KmsBackendConfig::AwsKms {
|
||
|
|
// region: "us-east-1".to_string(),
|
||
|
|
// key_id,
|
||
|
|
// assume_role: None,
|
||
|
|
// };
|
||
|
|
//
|
||
|
|
// let service = KmsService::new(config).await.unwrap();
|
||
|
|
//
|
||
|
|
// let plaintext = b"Hello, AWS KMS!";
|
||
|
|
// let mut context = EncryptionContext::new();
|
||
|
|
// context.add("test", "integration");
|
||
|
|
//
|
||
|
|
// // Encrypt
|
||
|
|
// let ciphertext = service.encrypt(plaintext, &context).await.unwrap();
|
||
|
|
// assert!(!ciphertext.is_empty());
|
||
|
|
// assert_ne!(ciphertext, plaintext);
|
||
|
|
//
|
||
|
|
// // Decrypt
|
||
|
|
// let decrypted = service.decrypt(&ciphertext, &context).await.unwrap();
|
||
|
|
// assert_eq!(decrypted, plaintext);
|
||
|
|
// }
|
||
|
|
//
|
||
|
|
// /// Test data key generation with AWS KMS
|
||
|
|
// #[tokio::test]
|
||
|
|
// #[ignore] // Requires AWS KMS
|
||
|
|
// async fn test_aws_kms_generate_data_key() {
|
||
|
|
// let key_id = std::env::var("AWS_KMS_KEY_ID").expect("AWS_KMS_KEY_ID not
|
||
|
|
// set");
|
||
|
|
//
|
||
|
|
// let config = KmsBackendConfig::AwsKms {
|
||
|
|
// region: "us-east-1".to_string(),
|
||
|
|
// key_id,
|
||
|
|
// assume_role: None,
|
||
|
|
// };
|
||
|
|
//
|
||
|
|
// let service = KmsService::new(config).await.unwrap();
|
||
|
|
//
|
||
|
|
// // Generate AES-256 data key
|
||
|
|
// let data_key =
|
||
|
|
// service.generate_data_key(&KeySpec::Aes256).await.unwrap();
|
||
|
|
//
|
||
|
|
// assert_eq!(data_key.plaintext.len(), 32); // 256 bits = 32 bytes
|
||
|
|
// assert!(!data_key.ciphertext.is_empty());
|
||
|
|
// assert!(!data_key.key_id.is_empty());
|
||
|
|
// }
|
||
|
|
//
|
||
|
|
// /// Test envelope encryption with AWS KMS
|
||
|
|
// #[tokio::test]
|
||
|
|
// #[ignore] // Requires AWS KMS
|
||
|
|
// async fn test_aws_kms_envelope_encryption() {
|
||
|
|
// let key_id = std::env::var("AWS_KMS_KEY_ID").expect("AWS_KMS_KEY_ID not
|
||
|
|
// set");
|
||
|
|
//
|
||
|
|
// let config = KmsBackendConfig::AwsKms {
|
||
|
|
// region: "us-east-1".to_string(),
|
||
|
|
// key_id,
|
||
|
|
// assume_role: None,
|
||
|
|
// };
|
||
|
|
//
|
||
|
|
// let service = KmsService::new(config).await.unwrap();
|
||
|
|
//
|
||
|
|
// let plaintext = b"Hello, envelope encryption!";
|
||
|
|
//
|
||
|
|
// // Envelope encrypt
|
||
|
|
// let envelope_ciphertext =
|
||
|
|
// service.envelope_encrypt(plaintext).await.unwrap(); assert!(!
|
||
|
|
// envelope_ciphertext.is_empty());
|
||
|
|
//
|
||
|
|
// // Envelope decrypt
|
||
|
|
// let decrypted =
|
||
|
|
// service.envelope_decrypt(&envelope_ciphertext).await.unwrap(); assert_eq!
|
||
|
|
// (decrypted, plaintext); }
|
||
|
|
|
||
|
|
/// Test health check
|
||
|
|
#[tokio::test]
|
||
|
|
#[ignore] // Requires backend
|
||
|
|
async fn test_health_check() {
|
||
|
|
let config = KmsBackendConfig::Rustyvault {
|
||
|
|
server_url: "http://localhost:8200".to_string(),
|
||
|
|
token: std::env::var("RUSTYVAULT_TOKEN").ok(),
|
||
|
|
mount_point: "transit".to_string(),
|
||
|
|
key_name: "test-key".to_string(),
|
||
|
|
tls_verify: false,
|
||
|
|
};
|
||
|
|
|
||
|
|
let service = KmsService::new(config).await.unwrap();
|
||
|
|
let healthy = service.health_check().await.unwrap();
|
||
|
|
assert!(healthy);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Test operations counter
|
||
|
|
#[tokio::test]
|
||
|
|
async fn test_operations_counter() {
|
||
|
|
// Use a mock or test config
|
||
|
|
let config = KmsBackendConfig::Rustyvault {
|
||
|
|
server_url: "http://localhost:8200".to_string(),
|
||
|
|
token: Some("test-token".to_string()),
|
||
|
|
mount_point: "transit".to_string(),
|
||
|
|
key_name: "test-key".to_string(),
|
||
|
|
tls_verify: false,
|
||
|
|
};
|
||
|
|
|
||
|
|
if let Ok(service) = KmsService::new(config).await {
|
||
|
|
let initial_count = service.get_operations_count().await;
|
||
|
|
assert_eq!(initial_count, 0);
|
||
|
|
// get_uptime() returns u64, always >= 0 by type
|
||
|
|
let _uptime = service.get_uptime();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Test context-based encryption (ensures context is enforced)
|
||
|
|
#[tokio::test]
|
||
|
|
#[ignore] // Requires backend
|
||
|
|
async fn test_context_enforcement() {
|
||
|
|
let config = KmsBackendConfig::Rustyvault {
|
||
|
|
server_url: "http://localhost:8200".to_string(),
|
||
|
|
token: std::env::var("RUSTYVAULT_TOKEN").ok(),
|
||
|
|
mount_point: "transit".to_string(),
|
||
|
|
key_name: "test-key".to_string(),
|
||
|
|
tls_verify: false,
|
||
|
|
};
|
||
|
|
|
||
|
|
let service = KmsService::new(config).await.unwrap();
|
||
|
|
|
||
|
|
let plaintext = b"Context-sensitive data";
|
||
|
|
|
||
|
|
let mut encrypt_context = EncryptionContext::new();
|
||
|
|
encrypt_context.add("purpose", "testing");
|
||
|
|
encrypt_context.add("level", "critical");
|
||
|
|
|
||
|
|
// Encrypt with context
|
||
|
|
let ciphertext = service.encrypt(plaintext, &encrypt_context).await.unwrap();
|
||
|
|
|
||
|
|
// Try to decrypt with wrong context (should fail)
|
||
|
|
let mut wrong_context = EncryptionContext::new();
|
||
|
|
wrong_context.add("purpose", "wrong");
|
||
|
|
|
||
|
|
let _result = service.decrypt(&ciphertext, &wrong_context).await;
|
||
|
|
// Note: Vault enforces context, so this should fail
|
||
|
|
// AWS KMS also enforces context when AAD is used
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Performance test: measure encryption throughput
|
||
|
|
#[tokio::test]
|
||
|
|
#[ignore] // Performance test, run manually
|
||
|
|
async fn test_encryption_performance() {
|
||
|
|
let config = KmsBackendConfig::Rustyvault {
|
||
|
|
server_url: "http://localhost:8200".to_string(),
|
||
|
|
token: std::env::var("RUSTYVAULT_TOKEN").ok(),
|
||
|
|
mount_point: "transit".to_string(),
|
||
|
|
key_name: "test-key".to_string(),
|
||
|
|
tls_verify: false,
|
||
|
|
};
|
||
|
|
|
||
|
|
let service = KmsService::new(config).await.unwrap();
|
||
|
|
|
||
|
|
let plaintext = b"Performance test data";
|
||
|
|
let context = EncryptionContext::new();
|
||
|
|
|
||
|
|
let iterations = 100;
|
||
|
|
let start = std::time::Instant::now();
|
||
|
|
|
||
|
|
for _ in 0..iterations {
|
||
|
|
let _ = service.encrypt(plaintext, &context).await.unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
let elapsed = start.elapsed();
|
||
|
|
let ops_per_sec = iterations as f64 / elapsed.as_secs_f64();
|
||
|
|
|
||
|
|
println!(
|
||
|
|
"Encryption throughput: {:.2} ops/sec ({} iterations in {:.2}s)",
|
||
|
|
ops_per_sec,
|
||
|
|
iterations,
|
||
|
|
elapsed.as_secs_f64()
|
||
|
|
);
|
||
|
|
}
|