Rust · 13631 bytes Raw Blame History
1 //! Security module for ZephyrFS
2 //!
3 //! Provides comprehensive security features including chunk isolation,
4 //! malicious content detection, and military-grade security boundaries.
5
6 pub mod chunk_isolation;
7 pub mod malicious_detection;
8
9 pub use chunk_isolation::{
10 ChunkSecurityManager, IsolatedChunk, IsolationLevel, ChunkAccessFlags, SecurityEvent,
11 IsolationConfig, ChunkStatus, ThreatLevel
12 };
13 pub use malicious_detection::{
14 MaliciousContentDetector, ThreatAnalysisResult, QuarantineManager, QuarantineStats,
15 ThreatIndicator, DetectionConfig, QuarantineStatus
16 };
17
18 use anyhow::Result;
19 use serde::{Deserialize, Serialize};
20 use std::collections::HashMap;
21 use uuid::Uuid;
22 use crate::crypto::EncryptedData;
23
24 /// Security configuration for the entire system
25 #[derive(Debug, Clone, Serialize, Deserialize)]
26 pub struct SecurityConfig {
27 /// Chunk isolation configuration
28 pub isolation_config: chunk_isolation::IsolationConfig,
29 /// Malicious content detection configuration
30 pub detection_config: malicious_detection::DetectionConfig,
31 /// Global security policies
32 pub global_policies: GlobalSecurityPolicies,
33 }
34
35 /// Global security policies
36 #[derive(Debug, Clone, Serialize, Deserialize)]
37 pub struct GlobalSecurityPolicies {
38 /// Minimum isolation level for new chunks
39 pub minimum_isolation_level: IsolationLevel,
40 /// Automatic quarantine on threat detection
41 pub auto_quarantine_enabled: bool,
42 /// Maximum threat level before immediate quarantine
43 pub quarantine_threshold: ThreatLevel,
44 /// Security audit logging enabled
45 pub audit_logging_enabled: bool,
46 /// Zero-knowledge enforcement
47 pub zero_knowledge_enforced: bool,
48 }
49
50 impl Default for SecurityConfig {
51 fn default() -> Self {
52 Self {
53 isolation_config: chunk_isolation::IsolationConfig::default(),
54 detection_config: malicious_detection::DetectionConfig::default(),
55 global_policies: GlobalSecurityPolicies {
56 minimum_isolation_level: IsolationLevel::Standard,
57 auto_quarantine_enabled: true,
58 quarantine_threshold: ThreatLevel::Medium,
59 audit_logging_enabled: true,
60 zero_knowledge_enforced: true,
61 },
62 }
63 }
64 }
65
66 /// Unified security manager combining all security systems
67 pub struct UnifiedSecurityManager {
68 chunk_security: ChunkSecurityManager,
69 threat_detector: MaliciousContentDetector,
70 quarantine_manager: QuarantineManager,
71 config: SecurityConfig,
72 }
73
74 impl UnifiedSecurityManager {
75 /// Create new unified security manager
76 pub fn new(config: SecurityConfig) -> Result<Self> {
77 let chunk_security = ChunkSecurityManager::new();
78 let threat_detector = MaliciousContentDetector::new();
79 let quarantine_manager = QuarantineManager::new();
80
81 Ok(Self {
82 chunk_security,
83 threat_detector,
84 quarantine_manager,
85 config,
86 })
87 }
88
89 /// Process new chunk with comprehensive security analysis
90 pub async fn process_new_chunk(
91 &mut self,
92 chunk_id: Uuid,
93 encrypted_data: &[u8],
94 metadata: HashMap<String, String>,
95 ) -> Result<ChunkSecurityDecision> {
96 // Step 1: Create encrypted data struct with production-ready crypto
97 use rand::RngCore;
98 let mut rng = rand::thread_rng();
99 let mut nonce = [0u8; 12];
100 rng.fill_bytes(&mut nonce);
101
102 let encrypted_data_struct = EncryptedData {
103 segment_index: 0,
104 ciphertext: encrypted_data.to_vec(),
105 nonce, // Cryptographically secure random nonce
106 aad: Vec::new(),
107 key_path: vec![chunk_id.as_u128() as u32], // Derive from chunk ID
108 };
109
110 // Step 2: Initial threat analysis
111 let threat_analysis = self.threat_detector
112 .analyze_content(&encrypted_data_struct, &metadata)
113 .await?;
114
115 // Step 3: Determine isolation level based on threat analysis
116 let isolation_level = self.determine_isolation_level(&threat_analysis);
117
118 // Step 4: Create isolated chunk
119 let isolated_chunk = self.chunk_security.create_isolated_chunk(
120 encrypted_data_struct,
121 isolation_level,
122 ).await?;
123
124 // Step 4: Check if quarantine is needed
125 let quarantine_decision = if threat_analysis.overall_threat_level >= self.config.global_policies.quarantine_threshold {
126 self.quarantine_manager.quarantine_chunk(
127 chunk_id,
128 format!("Threat detected: {:?}", threat_analysis.recommended_actions),
129 threat_analysis.overall_threat_level,
130 true, // automated
131 ).await?;
132 QuarantineDecision::Quarantined
133 } else {
134 QuarantineDecision::Allowed
135 };
136
137 Ok(ChunkSecurityDecision {
138 chunk_id,
139 isolation_level,
140 threat_analysis,
141 quarantine_decision,
142 security_clearance: self.calculate_security_clearance(&threat_analysis, isolation_level),
143 })
144 }
145
146 /// Verify chunk access with security checks
147 pub async fn verify_chunk_access(
148 &self,
149 chunk_id: Uuid,
150 requested_access: ChunkAccessFlags,
151 requester_context: AccessContext,
152 ) -> Result<AccessDecision> {
153 // Get chunk security status
154 let chunk_status = self.chunk_security.get_chunk_status(chunk_id).await?;
155
156 // Check if chunk is quarantined
157 if self.quarantine_manager.is_quarantined(chunk_id).await? {
158 return Ok(AccessDecision::Denied {
159 reason: "Chunk is quarantined".to_string(),
160 });
161 }
162
163 // Convert ChunkAccessFlags to ChunkAccessType based on flags
164 let access_type = if requested_access.writable {
165 chunk_isolation::ChunkAccessType::Write
166 } else if requested_access.transmittable {
167 chunk_isolation::ChunkAccessType::Transmit
168 } else {
169 chunk_isolation::ChunkAccessType::Read // Default for readable or other cases
170 };
171
172 // Verify access permissions based on isolation level
173 let access_allowed = self.chunk_security.verify_access(
174 chunk_id,
175 access_type,
176 ).await?;
177
178 if access_allowed {
179 Ok(AccessDecision::Granted {
180 conditions: self.get_access_conditions(&chunk_status, &requester_context),
181 })
182 } else {
183 Ok(AccessDecision::Denied {
184 reason: "Insufficient security clearance".to_string(),
185 })
186 }
187 }
188
189 /// Get comprehensive security status for a chunk
190 pub async fn get_chunk_security_status(&self, chunk_id: Uuid) -> Result<ChunkSecurityStatus> {
191 let chunk_status = self.chunk_security.get_chunk_status(chunk_id).await?;
192 let quarantine_status = self.quarantine_manager.get_quarantine_status(chunk_id).await?;
193 let threat_history = self.threat_detector.get_threat_history(chunk_id).await;
194
195 Ok(ChunkSecurityStatus {
196 chunk_id,
197 isolation_level: chunk_status.isolation_level,
198 access_flags: chunk_status.access_flags,
199 quarantine_status,
200 threat_history,
201 last_security_scan: chunk_status.last_update,
202 security_score: self.calculate_security_score(&chunk_status, &quarantine_status),
203 })
204 }
205
206 /// Update security policies
207 pub fn update_policies(&mut self, new_policies: GlobalSecurityPolicies) -> Result<()> {
208 self.config.global_policies = new_policies;
209 self.chunk_security.update_config(self.config.isolation_config.clone())?;
210 self.threat_detector.update_config(self.config.detection_config.clone())?;
211 Ok(())
212 }
213
214 /// Determine appropriate isolation level based on threat analysis
215 fn determine_isolation_level(&self, analysis: &ThreatAnalysisResult) -> IsolationLevel {
216 match analysis.overall_threat_level {
217 ThreatLevel::None | ThreatLevel::Low => {
218 if self.config.global_policies.minimum_isolation_level > IsolationLevel::Standard {
219 self.config.global_policies.minimum_isolation_level
220 } else {
221 IsolationLevel::Standard
222 }
223 }
224 ThreatLevel::Medium => IsolationLevel::Enhanced,
225 ThreatLevel::High | ThreatLevel::Critical => IsolationLevel::Quarantined,
226 }
227 }
228
229 /// Calculate security clearance level
230 fn calculate_security_clearance(
231 &self,
232 analysis: &ThreatAnalysisResult,
233 isolation_level: IsolationLevel,
234 ) -> SecurityClearance {
235 match (analysis.overall_threat_level, isolation_level) {
236 (ThreatLevel::None, IsolationLevel::Standard) => SecurityClearance::Public,
237 (ThreatLevel::Low, IsolationLevel::Standard) |
238 (ThreatLevel::None, IsolationLevel::Enhanced) => SecurityClearance::Internal,
239 (ThreatLevel::Medium, _) |
240 (ThreatLevel::Low, IsolationLevel::Enhanced) => SecurityClearance::Restricted,
241 (ThreatLevel::High, _) => SecurityClearance::Confidential,
242 (ThreatLevel::Critical, _) => SecurityClearance::TopSecret,
243 _ => SecurityClearance::Internal,
244 }
245 }
246
247 /// Get access conditions based on security status
248 fn get_access_conditions(
249 &self,
250 _chunk_status: &chunk_isolation::ChunkStatus,
251 _requester_context: &AccessContext,
252 ) -> Vec<AccessCondition> {
253 // Return appropriate access conditions
254 vec![AccessCondition::AuditLogging, AccessCondition::RateLimit]
255 }
256
257 /// Calculate overall security score for a chunk
258 fn calculate_security_score(
259 &self,
260 chunk_status: &chunk_isolation::ChunkStatus,
261 quarantine_status: &malicious_detection::QuarantineStatus,
262 ) -> f64 {
263 let isolation_score = match chunk_status.isolation_level {
264 IsolationLevel::Standard => 0.6,
265 IsolationLevel::Enhanced => 0.8,
266 IsolationLevel::Quarantined => 0.4, // Lower because it indicates detected threats
267 };
268
269 let quarantine_penalty = if quarantine_status.is_quarantined { 0.2 } else { 0.0 };
270
271 (isolation_score - quarantine_penalty).max(0.0).min(1.0)
272 }
273 }
274
275 /// Decision result for chunk security processing
276 #[derive(Debug, Clone)]
277 pub struct ChunkSecurityDecision {
278 pub chunk_id: Uuid,
279 pub isolation_level: IsolationLevel,
280 pub threat_analysis: ThreatAnalysisResult,
281 pub quarantine_decision: QuarantineDecision,
282 pub security_clearance: SecurityClearance,
283 }
284
285 /// Quarantine decision
286 #[derive(Debug, Clone)]
287 pub enum QuarantineDecision {
288 Allowed,
289 Quarantined,
290 PendingReview,
291 }
292
293 /// Security clearance levels
294 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
295 pub enum SecurityClearance {
296 Public,
297 Internal,
298 Restricted,
299 Confidential,
300 Secret,
301 TopSecret,
302 }
303
304 /// Access decision result
305 #[derive(Debug, Clone)]
306 pub enum AccessDecision {
307 Granted { conditions: Vec<AccessCondition> },
308 Denied { reason: String },
309 }
310
311 /// Conditions for chunk access
312 #[derive(Debug, Clone)]
313 pub enum AccessCondition {
314 AuditLogging,
315 RateLimit,
316 TimeRestriction,
317 LocationRestriction,
318 AdditionalAuthentication,
319 }
320
321 /// Context for access requests
322 #[derive(Debug, Clone)]
323 pub struct AccessContext {
324 pub requester_id: String,
325 pub security_clearance: SecurityClearance,
326 pub request_timestamp: u64,
327 pub request_origin: String,
328 pub additional_context: HashMap<String, String>,
329 }
330
331 /// Comprehensive security status for a chunk
332 #[derive(Debug, Clone)]
333 pub struct ChunkSecurityStatus {
334 pub chunk_id: Uuid,
335 pub isolation_level: IsolationLevel,
336 pub access_flags: ChunkAccessFlags,
337 pub quarantine_status: malicious_detection::QuarantineStatus,
338 pub threat_history: Vec<ThreatAnalysisResult>,
339 pub last_security_scan: u64,
340 pub security_score: f64,
341 }
342
343 #[cfg(test)]
344 mod tests {
345 use super::*;
346
347 #[tokio::test]
348 async fn test_unified_security_manager() -> Result<()> {
349 let config = SecurityConfig::default();
350 let mut security_manager = UnifiedSecurityManager::new(config)?;
351
352 let chunk_id = Uuid::new_v4();
353 let test_data = b"Test encrypted chunk data";
354 let metadata = HashMap::new();
355
356 let decision = security_manager
357 .process_new_chunk(chunk_id, test_data, metadata)
358 .await?;
359
360 assert_eq!(decision.chunk_id, chunk_id);
361 assert!(matches!(decision.quarantine_decision, QuarantineDecision::Allowed));
362
363 Ok(())
364 }
365
366 #[tokio::test]
367 async fn test_chunk_access_verification() -> Result<()> {
368 let config = SecurityConfig::default();
369 let security_manager = UnifiedSecurityManager::new(config)?;
370
371 let chunk_id = Uuid::new_v4();
372 let access_context = AccessContext {
373 requester_id: "test-user".to_string(),
374 security_clearance: SecurityClearance::Internal,
375 request_timestamp: 1234567890,
376 request_origin: "localhost".to_string(),
377 additional_context: HashMap::new(),
378 };
379
380 let access_decision = security_manager
381 .verify_chunk_access(chunk_id, ChunkAccessFlags::READ, access_context)
382 .await?;
383
384 // Should deny access for non-existent chunk
385 assert!(matches!(access_decision, AccessDecision::Denied { .. }));
386
387 Ok(())
388 }
389 }