x509_validator/
validated_chain.rs1use crate::Certificate;
2
3#[derive(Debug, Clone)]
5pub struct ValidatedCertificateChain<'a> {
6 certificates: Vec<Certificate<'a>>, }
8
9impl<'a> ValidatedCertificateChain<'a> {
10 pub fn new_unchecked(certificates: Vec<Certificate<'a>>) -> Self {
11 assert!(!certificates.is_empty());
12 Self { certificates }
13 }
14
15 pub fn leaf(&self) -> &Certificate<'a> {
16 &self.certificates[0]
17 }
18 pub fn root(&self) -> &Certificate<'a> {
19 self.certificates.last().unwrap()
20 }
21
22 pub fn iter(&self) -> impl Iterator<Item = &Certificate<'a>> {
23 self.certificates.iter()
24 }
25}
26
27#[cfg(test)]
28mod tests {
29 use x509_validator_testkit::{cert, issue_ca, issue_leaf, self_signed_ca_with};
30
31 use super::*;
32 use crate::CertificateExt;
33
34 fn leaf_intermediate_root() -> Vec<Certificate<'static>> {
36 let root = self_signed_ca_with("Root", |_| {});
37 let intermediate = issue_ca("Intermediate", &root, None, |_| {});
38 let leaf = issue_leaf("leaf.example.com", &["leaf.example.com"], &intermediate);
39
40 vec![cert(leaf), cert(intermediate.der), cert(root.der)]
41 }
42
43 #[test]
44 fn leaf_and_root_are_the_two_ends_of_the_chain() {
45 let chain = ValidatedCertificateChain::new_unchecked(leaf_intermediate_root());
46
47 assert_eq!(chain.leaf().subject().to_string(), "CN=leaf.example.com");
48 assert_eq!(chain.root().subject().to_string(), "CN=Root");
49 }
50
51 #[test]
52 fn root_is_the_self_signed_end_not_the_leaf() {
53 let chain = ValidatedCertificateChain::new_unchecked(leaf_intermediate_root());
54
55 let root = chain.root();
56 assert_eq!(root.subject_key(), root.issuer_key());
57 assert_ne!(chain.leaf().subject_key(), chain.leaf().issuer_key());
58 }
59
60 #[test]
61 fn iter_yields_the_chain_leaf_first() {
62 let chain = ValidatedCertificateChain::new_unchecked(leaf_intermediate_root());
63
64 let subjects: Vec<_> = chain
65 .iter()
66 .map(|c| c.subject().to_string())
67 .collect();
68
69 assert_eq!(
70 subjects,
71 ["CN=leaf.example.com", "CN=Intermediate", "CN=Root"]
72 );
73 }
74
75 #[test]
76 fn a_single_certificate_is_both_leaf_and_root() {
77 let root = cert(self_signed_ca_with("Root", |_| {}).der);
78 let chain = ValidatedCertificateChain::new_unchecked(vec![root]);
79
80 assert_eq!(chain.leaf().subject().to_string(), "CN=Root");
81 assert_eq!(chain.root().subject().to_string(), "CN=Root");
82 assert!(
83 chain
84 .leaf()
85 .has_same_identity_as(chain.root())
86 );
87 }
88
89 #[test]
90 fn new_unchecked_performs_no_validation() {
91 let a = cert(self_signed_ca_with("A", |_| {}).der);
95 let b = cert(self_signed_ca_with("B", |_| {}).der);
96
97 let chain = ValidatedCertificateChain::new_unchecked(vec![a, b]);
98
99 assert_ne!(chain.leaf().issuer_key(), chain.root().subject_key());
100 }
101
102 #[test]
103 #[should_panic]
104 fn constructing_an_empty_chain_panics() {
105 ValidatedCertificateChain::new_unchecked(Vec::new());
106 }
107}