1use crate::cert::Certificate;
11use crate::result::{PathFailure, VerificationResult};
12use chrono::{DateTime, Utc};
13
14#[derive(Debug, Clone)]
16pub struct CertPath<'a> {
17 pub leaf: &'a Certificate,
19 pub intermediates: Vec<&'a Certificate>,
21 pub root: &'a Certificate,
23}
24
25pub fn validate_path(path: &CertPath<'_>, now: DateTime<Utc>) -> VerificationResult {
29 let mut checks = Vec::new();
30 let mut valid = true;
31
32 let chain: Vec<&Certificate> = std::iter::once(path.leaf)
33 .chain(path.intermediates.iter().copied())
34 .chain(std::iter::once(path.root))
35 .collect();
36
37 for cert in &chain {
38 if !cert.is_within_validity(now) {
39 if now < cert.not_before_chrono() {
40 checks.push(PathFailure::NotYetValid);
41 } else {
42 checks.push(PathFailure::Expired);
43 }
44 valid = false;
45 }
46 }
47
48 if chain.len() > 16 {
49 checks.push(PathFailure::ChainTooLong);
50 valid = false;
51 }
52
53 VerificationResult { valid, checks }
54}
55
56pub fn verify_path_signatures<F>(path: &CertPath<'_>, verifier: F) -> VerificationResult
60where
61 F: Fn(&[u8], &[u8]) -> Result<(), String>,
62{
63 let mut checks = Vec::new();
64 let mut valid = true;
65
66 let chain: Vec<&Certificate> = std::iter::once(path.leaf)
67 .chain(path.intermediates.iter().copied())
68 .chain(std::iter::once(path.root))
69 .collect();
70
71 for i in 0..chain.len().saturating_sub(1) {
72 let child = chain[i];
73 let parent = chain[i + 1];
74 match verifier(parent.public_key_bytes(), child.to_der().as_slice()) {
75 Ok(()) => {}
76 Err(_) => {
77 checks.push(PathFailure::SignatureInvalid);
78 valid = false;
79 }
80 }
81 }
82
83 VerificationResult { valid, checks }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn empty_path_is_valid() {
92 let now = Utc::now();
94 let _ = now;
95 }
96}