chie_crypto/
compliance.rs

1//! FIPS 140-3 Compliance Reporting
2//!
3//! This module provides compliance checking and reporting for FIPS 140-3 requirements.
4//! It helps verify that cryptographic operations meet federal standards for security.
5//!
6//! # FIPS 140-3 Overview
7//!
8//! FIPS 140-3 is a U.S. government standard for cryptographic module validation.
9//! It defines security requirements for cryptographic modules used in protecting
10//! sensitive information.
11//!
12//! # Features
13//!
14//! - Algorithm compliance verification
15//! - Key strength validation
16//! - Self-tests (Known Answer Tests)
17//! - Compliance report generation
18//! - Security level tracking (Levels 1-4)
19//! - Status monitoring and alerts
20//!
21//! # Example
22//!
23//! ```
24//! use chie_crypto::compliance::{ComplianceChecker, ComplianceAlgorithm, SecurityLevel};
25//!
26//! let mut checker = ComplianceChecker::new(SecurityLevel::Level1);
27//!
28//! // Register algorithms in use
29//! checker.register_algorithm(ComplianceAlgorithm::AES256);
30//! checker.register_algorithm(ComplianceAlgorithm::SHA256);
31//! checker.register_algorithm(ComplianceAlgorithm::Ed25519);
32//!
33//! // Run self-tests
34//! let test_results = checker.run_self_tests();
35//! assert!(test_results.all_passed());
36//!
37//! // Generate compliance report
38//! let report = checker.generate_report();
39//! println!("Compliance Status: {:?}", report.overall_status);
40//! ```
41
42use 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/// FIPS 140-3 security level
49#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
50pub enum SecurityLevel {
51    /// Level 1: Basic security requirements
52    Level1,
53    /// Level 2: Physical tamper-evidence
54    Level2,
55    /// Level 3: Physical tamper-resistance
56    Level3,
57    /// Level 4: Complete envelope protection
58    Level4,
59}
60
61/// Cryptographic algorithm for compliance checking
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
63pub enum ComplianceAlgorithm {
64    /// AES-256 encryption
65    AES256,
66    /// ChaCha20-Poly1305 authenticated encryption
67    ChaCha20Poly1305,
68    /// SHA-256 hashing
69    SHA256,
70    /// SHA-512 hashing
71    SHA512,
72    /// BLAKE3 hashing
73    BLAKE3,
74    /// Ed25519 signatures
75    Ed25519,
76    /// X25519 key exchange
77    X25519,
78    /// HMAC-SHA256
79    HMACSHA256,
80    /// HKDF key derivation
81    HKDF,
82    /// RSA-2048
83    RSA2048,
84    /// RSA-3072
85    RSA3072,
86    /// Kyber (Post-Quantum KEM)
87    Kyber,
88    /// Dilithium (Post-Quantum Signatures)
89    Dilithium,
90}
91
92impl ComplianceAlgorithm {
93    /// Check if algorithm is FIPS 140-3 approved
94    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    /// Get required minimum key size in bits
108    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/// Compliance status
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
125pub enum ComplianceStatus {
126    /// Fully compliant
127    Compliant,
128    /// Partially compliant (warnings)
129    PartiallyCompliant,
130    /// Non-compliant (errors)
131    NonCompliant,
132}
133
134/// Self-test result
135#[derive(Debug, Clone, Serialize, Deserialize)]
136pub struct SelfTestResult {
137    /// Test name
138    pub test_name: String,
139    /// Algorithm being tested
140    pub algorithm: ComplianceAlgorithm,
141    /// Test passed
142    pub passed: bool,
143    /// Error message if failed
144    pub error: Option<String>,
145    /// Test timestamp
146    pub timestamp: DateTime<Utc>,
147}
148
149/// Collection of self-test results
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct SelfTestResults {
152    /// Individual test results
153    pub tests: Vec<SelfTestResult>,
154    /// Overall pass/fail
155    pub all_passed: bool,
156}
157
158impl SelfTestResults {
159    /// Check if all tests passed
160    pub fn all_passed(&self) -> bool {
161        self.all_passed
162    }
163
164    /// Get failed tests
165    pub fn failed_tests(&self) -> Vec<&SelfTestResult> {
166        self.tests.iter().filter(|t| !t.passed).collect()
167    }
168}
169
170/// Compliance issue
171#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct ComplianceIssue {
173    /// Issue severity
174    pub severity: IssueSeverity,
175    /// Description
176    pub description: String,
177    /// Algorithm affected
178    pub algorithm: Option<ComplianceAlgorithm>,
179    /// Recommendation
180    pub recommendation: String,
181}
182
183/// Issue severity
184#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
185pub enum IssueSeverity {
186    /// Informational
187    Info,
188    /// Warning
189    Warning,
190    /// Error
191    Error,
192    /// Critical
193    Critical,
194}
195
196/// Compliance report
197#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct ComplianceReport {
199    /// Security level
200    pub security_level: SecurityLevel,
201    /// Overall compliance status
202    pub overall_status: ComplianceStatus,
203    /// Algorithms in use
204    pub algorithms: Vec<ComplianceAlgorithm>,
205    /// FIPS-approved algorithms
206    pub fips_approved: Vec<ComplianceAlgorithm>,
207    /// Non-approved algorithms
208    pub non_approved: Vec<ComplianceAlgorithm>,
209    /// Self-test results
210    pub self_test_results: SelfTestResults,
211    /// Compliance issues
212    pub issues: Vec<ComplianceIssue>,
213    /// Report timestamp
214    pub timestamp: DateTime<Utc>,
215}
216
217impl ComplianceReport {
218    /// Export report to JSON
219    pub fn to_json(&self) -> Result<String, serde_json::Error> {
220        serde_json::to_string_pretty(self)
221    }
222}
223
224/// FIPS 140-3 compliance checker
225#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct ComplianceChecker {
227    /// Target security level
228    security_level: SecurityLevel,
229    /// Registered algorithms
230    algorithms: Vec<ComplianceAlgorithm>,
231    /// Issues found
232    issues: Vec<ComplianceIssue>,
233}
234
235impl ComplianceChecker {
236    /// Create a new compliance checker
237    pub fn new(security_level: SecurityLevel) -> Self {
238        Self {
239            security_level,
240            algorithms: Vec::new(),
241            issues: Vec::new(),
242        }
243    }
244
245    /// Register an algorithm in use
246    pub fn register_algorithm(&mut self, algorithm: ComplianceAlgorithm) {
247        if !self.algorithms.contains(&algorithm) {
248            self.algorithms.push(algorithm);
249
250            // Check if algorithm is FIPS approved
251            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    /// Run self-tests (Known Answer Tests)
263    pub fn run_self_tests(&mut self) -> SelfTestResults {
264        let tests = vec![
265            // Test ChaCha20-Poly1305 encryption
266            self.test_chacha20(),
267            // Test BLAKE3 hashing
268            self.test_blake3(),
269            // Test Ed25519 signing
270            self.test_ed25519(),
271        ];
272
273        let all_passed = tests.iter().all(|t| t.passed);
274
275        SelfTestResults { tests, all_passed }
276    }
277
278    /// Test ChaCha20-Poly1305 encryption
279    fn test_chacha20(&self) -> SelfTestResult {
280        let test_name = "ChaCha20-Poly1305 KAT".to_string();
281        let algorithm = ComplianceAlgorithm::ChaCha20Poly1305;
282
283        // Known Answer Test
284        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    /// Test BLAKE3 hashing
323    fn test_blake3(&self) -> SelfTestResult {
324        let test_name = "BLAKE3 KAT".to_string();
325        let algorithm = ComplianceAlgorithm::BLAKE3;
326
327        // Known Answer Test
328        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    /// Test Ed25519 signing
348    fn test_ed25519(&self) -> SelfTestResult {
349        let test_name = "Ed25519 KAT".to_string();
350        let algorithm = ComplianceAlgorithm::Ed25519;
351
352        // Known Answer Test
353        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    /// Validate key strength
373    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    /// Generate compliance report
397    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        // Determine overall status
415        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    /// Get current issues
446    pub fn issues(&self) -> &[ComplianceIssue] {
447        &self.issues
448    }
449
450    /// Clear all issues
451    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        // Valid key strength
499        assert!(checker.validate_key_strength(ComplianceAlgorithm::AES256, 256));
500
501        // Invalid key strength
502        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); // Too weak
537
538        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        // Should only register once
617        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}