1use crate::encryption::{decrypt, encrypt, generate_key, generate_nonce};
43use crate::hash::hash;
44use crate::signing::KeyPair;
45use chrono::{DateTime, Utc};
46use serde::{Deserialize, Serialize};
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
50pub enum SecurityLevel {
51 Level1,
53 Level2,
55 Level3,
57 Level4,
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
63pub enum ComplianceAlgorithm {
64 AES256,
66 ChaCha20Poly1305,
68 SHA256,
70 SHA512,
72 BLAKE3,
74 Ed25519,
76 X25519,
78 HMACSHA256,
80 HKDF,
82 RSA2048,
84 RSA3072,
86 Kyber,
88 Dilithium,
90}
91
92impl ComplianceAlgorithm {
93 pub fn is_fips_approved(&self) -> bool {
95 matches!(
96 self,
97 ComplianceAlgorithm::AES256
98 | ComplianceAlgorithm::SHA256
99 | ComplianceAlgorithm::SHA512
100 | ComplianceAlgorithm::HMACSHA256
101 | ComplianceAlgorithm::HKDF
102 | ComplianceAlgorithm::RSA2048
103 | ComplianceAlgorithm::RSA3072
104 )
105 }
106
107 pub fn min_key_size(&self) -> usize {
109 match self {
110 ComplianceAlgorithm::AES256 => 256,
111 ComplianceAlgorithm::ChaCha20Poly1305 => 256,
112 ComplianceAlgorithm::Ed25519 => 256,
113 ComplianceAlgorithm::X25519 => 256,
114 ComplianceAlgorithm::RSA2048 => 2048,
115 ComplianceAlgorithm::RSA3072 => 3072,
116 ComplianceAlgorithm::Kyber => 256,
117 ComplianceAlgorithm::Dilithium => 256,
118 _ => 0,
119 }
120 }
121}
122
123#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
125pub enum ComplianceStatus {
126 Compliant,
128 PartiallyCompliant,
130 NonCompliant,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
136pub struct SelfTestResult {
137 pub test_name: String,
139 pub algorithm: ComplianceAlgorithm,
141 pub passed: bool,
143 pub error: Option<String>,
145 pub timestamp: DateTime<Utc>,
147}
148
149#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct SelfTestResults {
152 pub tests: Vec<SelfTestResult>,
154 pub all_passed: bool,
156}
157
158impl SelfTestResults {
159 pub fn all_passed(&self) -> bool {
161 self.all_passed
162 }
163
164 pub fn failed_tests(&self) -> Vec<&SelfTestResult> {
166 self.tests.iter().filter(|t| !t.passed).collect()
167 }
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct ComplianceIssue {
173 pub severity: IssueSeverity,
175 pub description: String,
177 pub algorithm: Option<ComplianceAlgorithm>,
179 pub recommendation: String,
181}
182
183#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
185pub enum IssueSeverity {
186 Info,
188 Warning,
190 Error,
192 Critical,
194}
195
196#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct ComplianceReport {
199 pub security_level: SecurityLevel,
201 pub overall_status: ComplianceStatus,
203 pub algorithms: Vec<ComplianceAlgorithm>,
205 pub fips_approved: Vec<ComplianceAlgorithm>,
207 pub non_approved: Vec<ComplianceAlgorithm>,
209 pub self_test_results: SelfTestResults,
211 pub issues: Vec<ComplianceIssue>,
213 pub timestamp: DateTime<Utc>,
215}
216
217impl ComplianceReport {
218 pub fn to_json(&self) -> Result<String, serde_json::Error> {
220 serde_json::to_string_pretty(self)
221 }
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct ComplianceChecker {
227 security_level: SecurityLevel,
229 algorithms: Vec<ComplianceAlgorithm>,
231 issues: Vec<ComplianceIssue>,
233}
234
235impl ComplianceChecker {
236 pub fn new(security_level: SecurityLevel) -> Self {
238 Self {
239 security_level,
240 algorithms: Vec::new(),
241 issues: Vec::new(),
242 }
243 }
244
245 pub fn register_algorithm(&mut self, algorithm: ComplianceAlgorithm) {
247 if !self.algorithms.contains(&algorithm) {
248 self.algorithms.push(algorithm);
249
250 if !algorithm.is_fips_approved() {
252 self.issues.push(ComplianceIssue {
253 severity: IssueSeverity::Warning,
254 description: format!("{:?} is not FIPS 140-3 approved", algorithm),
255 algorithm: Some(algorithm),
256 recommendation: "Consider using FIPS-approved alternatives".to_string(),
257 });
258 }
259 }
260 }
261
262 pub fn run_self_tests(&mut self) -> SelfTestResults {
264 let tests = vec![
265 self.test_chacha20(),
267 self.test_blake3(),
269 self.test_ed25519(),
271 ];
272
273 let all_passed = tests.iter().all(|t| t.passed);
274
275 SelfTestResults { tests, all_passed }
276 }
277
278 fn test_chacha20(&self) -> SelfTestResult {
280 let test_name = "ChaCha20-Poly1305 KAT".to_string();
281 let algorithm = ComplianceAlgorithm::ChaCha20Poly1305;
282
283 let plaintext = b"Test message for KAT";
285 let key = generate_key();
286 let nonce = generate_nonce();
287
288 match encrypt(plaintext, &key, &nonce) {
289 Ok(ciphertext) => match decrypt(&ciphertext, &key, &nonce) {
290 Ok(decrypted) => {
291 let passed = decrypted == plaintext;
292 SelfTestResult {
293 test_name,
294 algorithm,
295 passed,
296 error: if passed {
297 None
298 } else {
299 Some("Decryption mismatch".to_string())
300 },
301 timestamp: Utc::now(),
302 }
303 }
304 Err(e) => SelfTestResult {
305 test_name,
306 algorithm,
307 passed: false,
308 error: Some(format!("Decryption failed: {:?}", e)),
309 timestamp: Utc::now(),
310 },
311 },
312 Err(e) => SelfTestResult {
313 test_name,
314 algorithm,
315 passed: false,
316 error: Some(format!("Encryption failed: {:?}", e)),
317 timestamp: Utc::now(),
318 },
319 }
320 }
321
322 fn test_blake3(&self) -> SelfTestResult {
324 let test_name = "BLAKE3 KAT".to_string();
325 let algorithm = ComplianceAlgorithm::BLAKE3;
326
327 let input = b"The quick brown fox jumps over the lazy dog";
329 let hash1 = hash(input);
330 let hash2 = hash(input);
331
332 let passed = hash1 == hash2 && hash1.len() == 32;
333
334 SelfTestResult {
335 test_name,
336 algorithm,
337 passed,
338 error: if passed {
339 None
340 } else {
341 Some("Hash mismatch or incorrect length".to_string())
342 },
343 timestamp: Utc::now(),
344 }
345 }
346
347 fn test_ed25519(&self) -> SelfTestResult {
349 let test_name = "Ed25519 KAT".to_string();
350 let algorithm = ComplianceAlgorithm::Ed25519;
351
352 let keypair = KeyPair::generate();
354 let message = b"Test message for signature";
355 let signature = keypair.sign(message);
356
357 let passed = keypair.verify(message, &signature);
358
359 SelfTestResult {
360 test_name,
361 algorithm,
362 passed,
363 error: if passed {
364 None
365 } else {
366 Some("Signature verification failed".to_string())
367 },
368 timestamp: Utc::now(),
369 }
370 }
371
372 pub fn validate_key_strength(
374 &mut self,
375 algorithm: ComplianceAlgorithm,
376 key_bits: usize,
377 ) -> bool {
378 let min_bits = algorithm.min_key_size();
379
380 if key_bits < min_bits {
381 self.issues.push(ComplianceIssue {
382 severity: IssueSeverity::Error,
383 description: format!(
384 "{:?} key strength ({} bits) below minimum ({} bits)",
385 algorithm, key_bits, min_bits
386 ),
387 algorithm: Some(algorithm),
388 recommendation: format!("Use at least {} bits for {:?}", min_bits, algorithm),
389 });
390 false
391 } else {
392 true
393 }
394 }
395
396 pub fn generate_report(&mut self) -> ComplianceReport {
398 let self_test_results = self.run_self_tests();
399
400 let fips_approved: Vec<ComplianceAlgorithm> = self
401 .algorithms
402 .iter()
403 .filter(|a| a.is_fips_approved())
404 .copied()
405 .collect();
406
407 let non_approved: Vec<ComplianceAlgorithm> = self
408 .algorithms
409 .iter()
410 .filter(|a| !a.is_fips_approved())
411 .copied()
412 .collect();
413
414 let has_errors = self
416 .issues
417 .iter()
418 .any(|i| matches!(i.severity, IssueSeverity::Error | IssueSeverity::Critical));
419
420 let has_warnings = self
421 .issues
422 .iter()
423 .any(|i| i.severity == IssueSeverity::Warning);
424
425 let overall_status = if has_errors || !self_test_results.all_passed {
426 ComplianceStatus::NonCompliant
427 } else if has_warnings || !non_approved.is_empty() {
428 ComplianceStatus::PartiallyCompliant
429 } else {
430 ComplianceStatus::Compliant
431 };
432
433 ComplianceReport {
434 security_level: self.security_level,
435 overall_status,
436 algorithms: self.algorithms.clone(),
437 fips_approved,
438 non_approved,
439 self_test_results,
440 issues: self.issues.clone(),
441 timestamp: Utc::now(),
442 }
443 }
444
445 pub fn issues(&self) -> &[ComplianceIssue] {
447 &self.issues
448 }
449
450 pub fn clear_issues(&mut self) {
452 self.issues.clear();
453 }
454}
455
456#[cfg(test)]
457mod tests {
458 use super::*;
459
460 #[test]
461 fn test_compliance_checker_basic() {
462 let checker = ComplianceChecker::new(SecurityLevel::Level1);
463 assert_eq!(checker.security_level, SecurityLevel::Level1);
464 }
465
466 #[test]
467 fn test_register_fips_approved_algorithm() {
468 let mut checker = ComplianceChecker::new(SecurityLevel::Level1);
469 checker.register_algorithm(ComplianceAlgorithm::AES256);
470
471 assert_eq!(checker.algorithms.len(), 1);
472 assert_eq!(checker.issues.len(), 0);
473 }
474
475 #[test]
476 fn test_register_non_approved_algorithm() {
477 let mut checker = ComplianceChecker::new(SecurityLevel::Level1);
478 checker.register_algorithm(ComplianceAlgorithm::ChaCha20Poly1305);
479
480 assert_eq!(checker.algorithms.len(), 1);
481 assert_eq!(checker.issues.len(), 1);
482 assert_eq!(checker.issues[0].severity, IssueSeverity::Warning);
483 }
484
485 #[test]
486 fn test_self_tests() {
487 let mut checker = ComplianceChecker::new(SecurityLevel::Level1);
488 let results = checker.run_self_tests();
489
490 assert!(results.all_passed());
491 assert_eq!(results.tests.len(), 3);
492 }
493
494 #[test]
495 fn test_key_strength_validation() {
496 let mut checker = ComplianceChecker::new(SecurityLevel::Level1);
497
498 assert!(checker.validate_key_strength(ComplianceAlgorithm::AES256, 256));
500
501 assert!(!checker.validate_key_strength(ComplianceAlgorithm::AES256, 128));
503 assert_eq!(checker.issues.len(), 1);
504 }
505
506 #[test]
507 fn test_generate_report_compliant() {
508 let mut checker = ComplianceChecker::new(SecurityLevel::Level1);
509 checker.register_algorithm(ComplianceAlgorithm::AES256);
510 checker.register_algorithm(ComplianceAlgorithm::SHA256);
511
512 let report = checker.generate_report();
513
514 assert_eq!(report.overall_status, ComplianceStatus::Compliant);
515 assert_eq!(report.fips_approved.len(), 2);
516 assert_eq!(report.non_approved.len(), 0);
517 }
518
519 #[test]
520 fn test_generate_report_partially_compliant() {
521 let mut checker = ComplianceChecker::new(SecurityLevel::Level1);
522 checker.register_algorithm(ComplianceAlgorithm::AES256);
523 checker.register_algorithm(ComplianceAlgorithm::ChaCha20Poly1305);
524
525 let report = checker.generate_report();
526
527 assert_eq!(report.overall_status, ComplianceStatus::PartiallyCompliant);
528 assert_eq!(report.fips_approved.len(), 1);
529 assert_eq!(report.non_approved.len(), 1);
530 }
531
532 #[test]
533 fn test_generate_report_non_compliant() {
534 let mut checker = ComplianceChecker::new(SecurityLevel::Level1);
535 checker.register_algorithm(ComplianceAlgorithm::AES256);
536 checker.validate_key_strength(ComplianceAlgorithm::AES256, 64); let report = checker.generate_report();
539
540 assert_eq!(report.overall_status, ComplianceStatus::NonCompliant);
541 }
542
543 #[test]
544 fn test_algorithm_is_fips_approved() {
545 assert!(ComplianceAlgorithm::AES256.is_fips_approved());
546 assert!(ComplianceAlgorithm::SHA256.is_fips_approved());
547 assert!(!ComplianceAlgorithm::ChaCha20Poly1305.is_fips_approved());
548 assert!(!ComplianceAlgorithm::BLAKE3.is_fips_approved());
549 }
550
551 #[test]
552 fn test_security_levels() {
553 assert!(SecurityLevel::Level1 < SecurityLevel::Level2);
554 assert!(SecurityLevel::Level2 < SecurityLevel::Level3);
555 assert!(SecurityLevel::Level3 < SecurityLevel::Level4);
556 }
557
558 #[test]
559 fn test_report_json_export() {
560 let mut checker = ComplianceChecker::new(SecurityLevel::Level1);
561 checker.register_algorithm(ComplianceAlgorithm::AES256);
562
563 let report = checker.generate_report();
564 let json = report.to_json().unwrap();
565
566 assert!(json.contains("AES256"));
567 assert!(json.contains("security_level"));
568 }
569
570 #[test]
571 fn test_failed_tests() {
572 let results = SelfTestResults {
573 tests: vec![
574 SelfTestResult {
575 test_name: "Test1".to_string(),
576 algorithm: ComplianceAlgorithm::AES256,
577 passed: true,
578 error: None,
579 timestamp: Utc::now(),
580 },
581 SelfTestResult {
582 test_name: "Test2".to_string(),
583 algorithm: ComplianceAlgorithm::SHA256,
584 passed: false,
585 error: Some("Error".to_string()),
586 timestamp: Utc::now(),
587 },
588 ],
589 all_passed: false,
590 };
591
592 let failed = results.failed_tests();
593 assert_eq!(failed.len(), 1);
594 assert_eq!(failed[0].test_name, "Test2");
595 }
596
597 #[test]
598 fn test_clear_issues() {
599 let mut checker = ComplianceChecker::new(SecurityLevel::Level1);
600 checker.register_algorithm(ComplianceAlgorithm::ChaCha20Poly1305);
601
602 assert_eq!(checker.issues.len(), 1);
603
604 checker.clear_issues();
605 assert_eq!(checker.issues.len(), 0);
606 }
607
608 #[test]
609 fn test_multiple_registrations_same_algorithm() {
610 let mut checker = ComplianceChecker::new(SecurityLevel::Level1);
611
612 checker.register_algorithm(ComplianceAlgorithm::AES256);
613 checker.register_algorithm(ComplianceAlgorithm::AES256);
614 checker.register_algorithm(ComplianceAlgorithm::AES256);
615
616 assert_eq!(checker.algorithms.len(), 1);
618 }
619
620 #[test]
621 fn test_min_key_sizes() {
622 assert_eq!(ComplianceAlgorithm::AES256.min_key_size(), 256);
623 assert_eq!(ComplianceAlgorithm::RSA2048.min_key_size(), 2048);
624 assert_eq!(ComplianceAlgorithm::RSA3072.min_key_size(), 3072);
625 }
626
627 #[test]
628 fn test_issue_severity_levels() {
629 let issue = ComplianceIssue {
630 severity: IssueSeverity::Critical,
631 description: "Test".to_string(),
632 algorithm: None,
633 recommendation: "Fix it".to_string(),
634 };
635
636 assert_eq!(issue.severity, IssueSeverity::Critical);
637 }
638}