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