Skip to main content

confium_pki/
result.rs

1//! Unified verification result shared across Confium PKI crates.
2
3use serde::{Deserialize, Serialize};
4
5/// Result of a verification operation (cert path, signature, CMS, etc.).
6#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7pub struct VerificationResult {
8    /// Overall validity — true iff every check passed.
9    pub valid: bool,
10    /// Per-check detail.
11    pub checks: Vec<PathFailure>,
12}
13
14/// Individual check failures.
15#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
16#[serde(tag = "type", rename_all = "snake_case")]
17pub enum PathFailure {
18    /// Certificate is expired.
19    Expired,
20    /// Certificate is not yet valid.
21    NotYetValid,
22    /// Signature verification failed.
23    SignatureInvalid,
24    /// Scope constraint violated.
25    ScopeViolation {
26        /// Expected scope value.
27        expected: String,
28        /// Actual scope value.
29        actual: String,
30    },
31    /// Chain exceeds max length.
32    ChainTooLong,
33    /// Root is not in trust store.
34    UntrustedRoot,
35    /// Certificate is revoked.
36    Revoked {
37        /// CRL distribution URL.
38        crl_url: String,
39        /// Revoked serial number.
40        serial: String,
41    },
42}
43
44impl VerificationResult {
45    /// Aggregate multiple verification results into one.
46    pub fn aggregate(results: &[VerificationResult]) -> Self {
47        let mut combined = VerificationResult {
48            valid: true,
49            checks: Vec::new(),
50        };
51        for r in results {
52            if !r.valid {
53                combined.valid = false;
54            }
55            combined.checks.extend(r.checks.iter().cloned());
56        }
57        combined
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn aggregate_passing_results() {
67        let r1 = VerificationResult {
68            valid: true,
69            checks: vec![],
70        };
71        let r2 = VerificationResult {
72            valid: true,
73            checks: vec![],
74        };
75        let combined = VerificationResult::aggregate(&[r1, r2]);
76        assert!(combined.valid);
77        assert!(combined.checks.is_empty());
78    }
79
80    #[test]
81    fn aggregate_with_failure_propagates() {
82        let r1 = VerificationResult {
83            valid: true,
84            checks: vec![],
85        };
86        let r2 = VerificationResult {
87            valid: false,
88            checks: vec![PathFailure::Expired],
89        };
90        let combined = VerificationResult::aggregate(&[r1, r2]);
91        assert!(!combined.valid);
92        assert_eq!(combined.checks.len(), 1);
93    }
94}