1use ntex_bytes::Bytes;
3
4use crate::x509::{Certificate, Error};
5
6#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct PeerCerts {
13 leaf: Certificate,
14 chain: Vec<Certificate>,
15}
16
17impl PeerCerts {
18 pub fn from_der(leaf: Bytes, chain: Vec<Bytes>) -> Result<Self, Error> {
27 let mut chain = chain.into_iter().peekable();
28 if chain.peek().is_some_and(|first| *first == leaf) {
29 chain.next();
30 }
31 let chain = chain
32 .map(Certificate::from_der)
33 .collect::<Result<Vec<_>, _>>()?;
34 Ok(PeerCerts {
35 leaf: Certificate::from_der(leaf)?,
36 chain,
37 })
38 }
39
40 #[must_use]
44 pub fn new(leaf: Certificate, chain: Vec<Certificate>) -> Self {
45 PeerCerts { leaf, chain }
46 }
47
48 #[must_use]
50 pub fn leaf(&self) -> &Certificate {
51 &self.leaf
52 }
53
54 #[must_use]
56 pub fn chain(&self) -> &[Certificate] {
57 &self.chain
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64 use crate::x509::testgen::{self, San};
65
66 #[test]
71 fn strips_leaf_from_chain() {
72 let k = testgen::key();
73 let san = San::default();
74 let ca = testgen::cert("ca", true, None, &k, &san, (-1, 1));
75 let k2 = testgen::key();
76 let leaf = testgen::cert("leaf", false, Some((&ca, &k)), &k2, &san, (-1, 1));
77 let leaf_der = leaf.der().clone();
78 let ca_der = ca.der().clone();
79
80 let p =
81 PeerCerts::from_der(leaf_der.clone(), vec![leaf_der.clone(), ca_der.clone()]).unwrap();
82 assert_eq!(p.leaf().subject_cn(), Some("leaf"));
83 assert_eq!(p.chain().len(), 1);
84 assert_eq!(p.chain()[0].subject_cn(), Some("ca"));
85
86 let p = PeerCerts::from_der(leaf_der.clone(), vec![ca_der]).unwrap();
87 assert_eq!(p.chain().len(), 1);
88 let p = PeerCerts::from_der(leaf_der.clone(), vec![]).unwrap();
89 assert_eq!(p.chain(), []);
90 assert!(PeerCerts::from_der(leaf_der, vec![Bytes::from_static(b"x")]).is_err());
91 }
92}