rustls/webpki/
anchors.rs

1use alloc::vec::Vec;
2use alloc::{fmt, format};
3
4use pki_types::{CertificateDer, TrustAnchor};
5use webpki::anchor_from_trusted_cert;
6
7use super::pki_error;
8#[cfg(feature = "logging")]
9use crate::log::{debug, trace};
10use crate::{DistinguishedName, Error};
11
12/// A container for root certificates able to provide a root-of-trust
13/// for connection authentication.
14#[derive(Clone)]
15pub struct RootCertStore {
16    /// The list of roots.
17    pub roots: Vec<TrustAnchor<'static>>,
18}
19
20impl RootCertStore {
21    /// Make a new, empty `RootCertStore`.
22    pub fn empty() -> Self {
23        Self { roots: Vec::new() }
24    }
25
26    /// Parse the given DER-encoded certificates and add all that can be parsed
27    /// in a best-effort fashion.
28    ///
29    /// This is because large collections of root certificates often
30    /// include ancient or syntactically invalid certificates.
31    ///
32    /// Returns the number of certificates added, and the number that were ignored.
33    pub fn add_parsable_certificates<'a>(
34        &mut self,
35        der_certs: impl IntoIterator<Item = CertificateDer<'a>>,
36    ) -> (usize, usize) {
37        let mut valid_count = 0;
38        let mut invalid_count = 0;
39
40        for der_cert in der_certs {
41            #[cfg_attr(not(feature = "logging"), allow(unused_variables))]
42            match anchor_from_trusted_cert(&der_cert) {
43                Ok(anchor) => {
44                    self.roots.push(anchor.to_owned());
45                    valid_count += 1;
46                }
47                Err(err) => {
48                    trace!("invalid cert der {:?}", der_cert.as_ref());
49                    debug!("certificate parsing failed: {:?}", err);
50                    invalid_count += 1;
51                }
52            };
53        }
54
55        debug!(
56            "add_parsable_certificates processed {} valid and {} invalid certs",
57            valid_count, invalid_count
58        );
59
60        (valid_count, invalid_count)
61    }
62
63    /// Add a single DER-encoded certificate to the store.
64    ///
65    /// This is suitable for a small set of root certificates that are expected to parse
66    /// successfully. For large collections of roots (for example from a system store) it
67    /// is expected that some of them might not be valid according to the rules rustls
68    /// implements. As long as a relatively limited number of certificates are affected,
69    /// this should not be a cause for concern. Use [`RootCertStore::add_parsable_certificates`]
70    /// in order to add as many valid roots as possible and to understand how many certificates
71    /// have been diagnosed as malformed.
72    pub fn add(&mut self, der: CertificateDer<'_>) -> Result<(), Error> {
73        self.roots.push(
74            anchor_from_trusted_cert(&der)
75                .map_err(pki_error)?
76                .to_owned(),
77        );
78        Ok(())
79    }
80
81    /// Return the DER encoded [`DistinguishedName`] of each trust anchor subject in the root
82    /// cert store.
83    ///
84    /// Each [`DistinguishedName`] will be a DER-encoded X.500 distinguished name, per
85    /// [RFC 5280 A.1], including the outer `SEQUENCE`.
86    ///
87    /// [RFC 5280 A.1]: https://www.rfc-editor.org/rfc/rfc5280#appendix-A.1
88    pub fn subjects(&self) -> Vec<DistinguishedName> {
89        self.roots
90            .iter()
91            .map(|ta| DistinguishedName::in_sequence(ta.subject.as_ref()))
92            .collect()
93    }
94
95    /// Return true if there are no certificates.
96    pub fn is_empty(&self) -> bool {
97        self.len() == 0
98    }
99
100    /// Say how many certificates are in the container.
101    pub fn len(&self) -> usize {
102        self.roots.len()
103    }
104}
105
106impl Extend<TrustAnchor<'static>> for RootCertStore {
107    fn extend<T: IntoIterator<Item = TrustAnchor<'static>>>(&mut self, iter: T) {
108        self.roots.extend(iter);
109    }
110}
111
112impl fmt::Debug for RootCertStore {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        f.debug_struct("RootCertStore")
115            .field("roots", &format!("({} roots)", &self.roots.len()))
116            .finish()
117    }
118}
119
120#[test]
121fn root_cert_store_debug() {
122    use core::iter;
123    use pki_types::Der;
124
125    let mut store = RootCertStore::empty();
126    let ta = TrustAnchor {
127        subject: Der::from_slice(&[]),
128        subject_public_key_info: Der::from_slice(&[]),
129        name_constraints: None,
130    };
131    store.extend(iter::repeat(ta).take(138));
132
133    assert_eq!(
134        format!("{:?}", store),
135        "RootCertStore { roots: \"(138 roots)\" }"
136    );
137}