rustls/
anchors.rs

1use webpki;
2
3use crate::key;
4#[cfg(feature = "logging")]
5use crate::log::{debug, trace};
6pub use crate::msgs::handshake::{DistinguishedName, DistinguishedNames};
7use crate::pemfile;
8use crate::x509;
9use std::io;
10
11/// This is like a `webpki::TrustAnchor`, except it owns
12/// rather than borrows its memory.  That prevents lifetimes
13/// leaking up the object tree.
14#[derive(Debug, Clone)]
15pub struct OwnedTrustAnchor {
16    subject: Vec<u8>,
17    spki: Vec<u8>,
18    name_constraints: Option<Vec<u8>>,
19}
20
21impl OwnedTrustAnchor {
22    /// Copy a `webpki::TrustAnchor` into owned memory
23    pub fn from_trust_anchor(t: &webpki::TrustAnchor) -> OwnedTrustAnchor {
24        OwnedTrustAnchor {
25            subject: t.subject.to_vec(),
26            spki: t.spki.to_vec(),
27            name_constraints: t.name_constraints.map(|x| x.to_vec()),
28        }
29    }
30
31    /// Get a `webpki::TrustAnchor` by borrowing the owned elements.
32    pub fn to_trust_anchor(&self) -> webpki::TrustAnchor {
33        webpki::TrustAnchor {
34            subject: &self.subject,
35            spki: &self.spki,
36            name_constraints: self
37                .name_constraints
38                .as_ref()
39                .map(Vec::as_slice),
40        }
41    }
42}
43
44impl From<webpki::TrustAnchor<'_>> for OwnedTrustAnchor {
45    fn from(t: webpki::TrustAnchor) -> OwnedTrustAnchor {
46        Self::from_trust_anchor(&t)
47    }
48}
49
50impl<'a> Into<webpki::TrustAnchor<'a>> for &'a OwnedTrustAnchor {
51    fn into(self) -> webpki::TrustAnchor<'a> {
52        self.to_trust_anchor()
53    }
54}
55
56/// A container for root certificates able to provide a root-of-trust
57/// for connection authentication.
58#[derive(Debug, Clone)]
59pub struct RootCertStore {
60    /// The list of roots.
61    pub roots: Vec<OwnedTrustAnchor>,
62}
63
64impl RootCertStore {
65    /// Make a new, empty `RootCertStore`.
66    pub fn empty() -> RootCertStore {
67        RootCertStore { roots: Vec::new() }
68    }
69
70    /// Return true if there are no certificates.
71    pub fn is_empty(&self) -> bool {
72        self.len() == 0
73    }
74
75    /// Say how many certificates are in the container.
76    pub fn len(&self) -> usize {
77        self.roots.len()
78    }
79
80    /// Return the Subject Names for certificates in the container.
81    pub fn get_subjects(&self) -> DistinguishedNames {
82        let mut r = DistinguishedNames::new();
83
84        for ota in &self.roots {
85            let mut name = Vec::new();
86            name.extend_from_slice(&ota.subject);
87            x509::wrap_in_sequence(&mut name);
88            r.push(DistinguishedName::new(name));
89        }
90
91        r
92    }
93
94    /// Add a single DER-encoded certificate to the store.
95    pub fn add(&mut self, der: &key::Certificate) -> Result<(), webpki::Error> {
96        let ta = webpki::trust_anchor_util::cert_der_as_trust_anchor(&der.0)?;
97
98        let ota = OwnedTrustAnchor::from_trust_anchor(&ta);
99        self.roots.push(ota);
100        Ok(())
101    }
102
103    /// Adds all the given TrustAnchors `anchors`.  This does not
104    /// fail.
105    pub fn add_server_trust_anchors(
106        &mut self,
107        &webpki::TLSServerTrustAnchors(anchors): &webpki::TLSServerTrustAnchors,
108    ) {
109        for ta in anchors {
110            self.roots
111                .push(OwnedTrustAnchor::from_trust_anchor(ta));
112        }
113    }
114
115    /// Parse a PEM file and add all certificates found inside.
116    /// Errors are non-specific; they may be io errors in `rd` and
117    /// PEM format errors, but not certificate validity errors.
118    ///
119    /// This is because large collections of root certificates often
120    /// include ancient or syntactically invalid certificates.  CAs
121    /// are competent like that.
122    ///
123    /// Returns the number of certificates added, and the number
124    /// which were extracted from the PEM but ultimately unsuitable.
125    pub fn add_pem_file(&mut self, rd: &mut dyn io::BufRead) -> Result<(usize, usize), ()> {
126        let ders = pemfile::certs(rd)?;
127        let mut valid_count = 0;
128        let mut invalid_count = 0;
129
130        for der in ders {
131            #[cfg_attr(not(feature = "logging"), allow(unused_variables))]
132            match self.add(&der) {
133                Ok(_) => valid_count += 1,
134                Err(err) => {
135                    trace!("invalid cert der {:?}", der);
136                    debug!("certificate parsing failed: {:?}", err);
137                    invalid_count += 1
138                }
139            }
140        }
141
142        debug!(
143            "add_pem_file processed {} valid and {} invalid certs",
144            valid_count, invalid_count
145        );
146
147        Ok((valid_count, invalid_count))
148    }
149}