rustls/webpki/
anchors.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use alloc::vec::Vec;
use alloc::{fmt, format};

use pki_types::{CertificateDer, TrustAnchor};
use webpki::anchor_from_trusted_cert;

use super::pki_error;
#[cfg(feature = "logging")]
use crate::log::{debug, trace};
use crate::{DistinguishedName, Error};

/// A container for root certificates able to provide a root-of-trust
/// for connection authentication.
#[derive(Clone)]
pub struct RootCertStore {
    /// The list of roots.
    pub roots: Vec<TrustAnchor<'static>>,
}

impl RootCertStore {
    /// Make a new, empty `RootCertStore`.
    pub fn empty() -> Self {
        Self { roots: Vec::new() }
    }

    /// Parse the given DER-encoded certificates and add all that can be parsed
    /// in a best-effort fashion.
    ///
    /// This is because large collections of root certificates often
    /// include ancient or syntactically invalid certificates.
    ///
    /// Returns the number of certificates added, and the number that were ignored.
    pub fn add_parsable_certificates<'a>(
        &mut self,
        der_certs: impl IntoIterator<Item = CertificateDer<'a>>,
    ) -> (usize, usize) {
        let mut valid_count = 0;
        let mut invalid_count = 0;

        for der_cert in der_certs {
            #[cfg_attr(not(feature = "logging"), allow(unused_variables))]
            match anchor_from_trusted_cert(&der_cert) {
                Ok(anchor) => {
                    self.roots.push(anchor.to_owned());
                    valid_count += 1;
                }
                Err(err) => {
                    trace!("invalid cert der {:?}", der_cert.as_ref());
                    debug!("certificate parsing failed: {:?}", err);
                    invalid_count += 1;
                }
            };
        }

        debug!(
            "add_parsable_certificates processed {} valid and {} invalid certs",
            valid_count, invalid_count
        );

        (valid_count, invalid_count)
    }

    /// Add a single DER-encoded certificate to the store.
    ///
    /// This is suitable for a small set of root certificates that are expected to parse
    /// successfully. For large collections of roots (for example from a system store) it
    /// is expected that some of them might not be valid according to the rules rustls
    /// implements. As long as a relatively limited number of certificates are affected,
    /// this should not be a cause for concern. Use [`RootCertStore::add_parsable_certificates`]
    /// in order to add as many valid roots as possible and to understand how many certificates
    /// have been diagnosed as malformed.
    pub fn add(&mut self, der: CertificateDer<'_>) -> Result<(), Error> {
        self.roots.push(
            anchor_from_trusted_cert(&der)
                .map_err(pki_error)?
                .to_owned(),
        );
        Ok(())
    }

    /// Return the DER encoded [`DistinguishedName`] of each trust anchor subject in the root
    /// cert store.
    ///
    /// Each [`DistinguishedName`] will be a DER-encoded X.500 distinguished name, per
    /// [RFC 5280 A.1], including the outer `SEQUENCE`.
    ///
    /// [RFC 5280 A.1]: https://www.rfc-editor.org/rfc/rfc5280#appendix-A.1
    pub fn subjects(&self) -> Vec<DistinguishedName> {
        self.roots
            .iter()
            .map(|ta| DistinguishedName::in_sequence(ta.subject.as_ref()))
            .collect()
    }

    /// Return true if there are no certificates.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Say how many certificates are in the container.
    pub fn len(&self) -> usize {
        self.roots.len()
    }
}

impl Extend<TrustAnchor<'static>> for RootCertStore {
    fn extend<T: IntoIterator<Item = TrustAnchor<'static>>>(&mut self, iter: T) {
        self.roots.extend(iter);
    }
}

impl fmt::Debug for RootCertStore {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("RootCertStore")
            .field("roots", &format!("({} roots)", &self.roots.len()))
            .finish()
    }
}

#[test]
fn root_cert_store_debug() {
    use core::iter;
    use pki_types::Der;

    let mut store = RootCertStore::empty();
    let ta = TrustAnchor {
        subject: Der::from_slice(&[]),
        subject_public_key_info: Der::from_slice(&[]),
        name_constraints: None,
    };
    store.extend(iter::repeat(ta).take(138));

    assert_eq!(
        format!("{:?}", store),
        "RootCertStore { roots: \"(138 roots)\" }"
    );
}