1#[cfg(feature = "logging")]
2use crate::log::{debug, trace};
3use crate::x509;
4use crate::{key, DistinguishedName};
5use crate::{CertificateError, Error};
67/// A trust anchor, commonly known as a "Root Certificate."
8#[derive(Debug, Clone)]
9pub struct OwnedTrustAnchor {
10 subject_dn_header_len: usize,
11 subject_dn: DistinguishedName,
12 spki: Vec<u8>,
13 name_constraints: Option<Vec<u8>>,
14}
1516impl OwnedTrustAnchor {
17/// Get a `webpki::TrustAnchor` by borrowing the owned elements.
18pub(crate) fn to_trust_anchor(&self) -> webpki::TrustAnchor {
19 webpki::TrustAnchor {
20 subject: &self.subject_dn.as_ref()[self.subject_dn_header_len..],
21 spki: &self.spki,
22 name_constraints: self.name_constraints.as_deref(),
23 }
24 }
2526/// Constructs an `OwnedTrustAnchor` from its components.
27 ///
28 /// All inputs are DER-encoded.
29 ///
30 /// `subject` is the [Subject] field of the trust anchor *without* the outer SEQUENCE
31 /// encoding.
32 ///
33 /// `spki` is the [SubjectPublicKeyInfo] field of the trust anchor.
34 ///
35 /// `name_constraints` is the [Name Constraints] to
36 /// apply for this trust anchor, if any.
37 ///
38 /// [Subject]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6
39 /// [SubjectPublicKeyInfo]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.7
40 /// [Name Constraints]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10
41pub fn from_subject_spki_name_constraints(
42 subject: impl Into<Vec<u8>>,
43 spki: impl Into<Vec<u8>>,
44 name_constraints: Option<impl Into<Vec<u8>>>,
45 ) -> Self {
46let (subject_dn, subject_dn_header_len) = {
47let mut subject = subject.into();
48let before_len = subject.len();
49 x509::wrap_in_sequence(&mut subject);
50let header_len = subject.len().saturating_sub(before_len);
51 (DistinguishedName::from(subject), header_len)
52 };
53Self {
54 subject_dn_header_len,
55 subject_dn,
56 spki: spki.into(),
57 name_constraints: name_constraints.map(|x| x.into()),
58 }
59 }
6061/// Return the subject field including its outer SEQUENCE encoding.
62 ///
63 /// This can be decoded using [x509-parser's FromDer trait](https://docs.rs/x509-parser/latest/x509_parser/prelude/trait.FromDer.html).
64 ///
65 /// ```ignore
66 /// use x509_parser::prelude::FromDer;
67 /// println!("{}", x509_parser::x509::X509Name::from_der(anchor.subject())?.1);
68 /// ```
69pub fn subject(&self) -> &DistinguishedName {
70&self.subject_dn
71 }
72}
7374/// A container for root certificates able to provide a root-of-trust
75/// for connection authentication.
76#[derive(Debug, Clone)]
77pub struct RootCertStore {
78/// The list of roots.
79pub roots: Vec<OwnedTrustAnchor>,
80}
8182impl RootCertStore {
83/// Make a new, empty `RootCertStore`.
84pub fn empty() -> Self {
85Self { roots: Vec::new() }
86 }
8788/// Return true if there are no certificates.
89pub fn is_empty(&self) -> bool {
90self.len() == 0
91}
9293/// Say how many certificates are in the container.
94pub fn len(&self) -> usize {
95self.roots.len()
96 }
9798/// Add a single DER-encoded certificate to the store.
99 ///
100 /// This is suitable for a small set of root certificates that are expected to parse
101 /// successfully. For large collections of roots (for example from a system store) it
102 /// is expected that some of them might not be valid according to the rules rustls
103 /// implements. As long as a relatively limited number of certificates are affected,
104 /// this should not be a cause for concern. Use [`RootCertStore::add_parsable_certificates`]
105 /// in order to add as many valid roots as possible and to understand how many certificates
106 /// have been diagnosed as malformed.
107pub fn add(&mut self, der: &key::Certificate) -> Result<(), Error> {
108self.add_internal(&der.0)
109 }
110111/// Adds all the given TrustAnchors `anchors`. This does not
112 /// fail.
113pub fn add_trust_anchors(&mut self, trust_anchors: impl Iterator<Item = OwnedTrustAnchor>) {
114self.roots.extend(trust_anchors);
115 }
116117/// Adds all the given TrustAnchors `anchors`. This does not
118 /// fail.
119#[deprecated(since = "0.21.6", note = "Please use `add_trust_anchors` instead")]
120pub fn add_server_trust_anchors(
121&mut self,
122 trust_anchors: impl Iterator<Item = OwnedTrustAnchor>,
123 ) {
124self.add_trust_anchors(trust_anchors);
125 }
126127/// Parse the given DER-encoded certificates and add all that can be parsed
128 /// in a best-effort fashion.
129 ///
130 /// This is because large collections of root certificates often
131 /// include ancient or syntactically invalid certificates.
132 ///
133 /// Returns the number of certificates added, and the number that were ignored.
134pub fn add_parsable_certificates(&mut self, der_certs: &[impl AsRef<[u8]>]) -> (usize, usize) {
135let mut valid_count = 0;
136let mut invalid_count = 0;
137138for der_cert in der_certs {
139#[cfg_attr(not(feature = "logging"), allow(unused_variables))]
140match self.add_internal(der_cert.as_ref()) {
141Ok(_) => valid_count += 1,
142Err(err) => {
143trace!("invalid cert der {:?}", der_cert.as_ref());
144debug!("certificate parsing failed: {:?}", err);
145 invalid_count += 1;
146 }
147 }
148 }
149150debug!(
151"add_parsable_certificates processed {} valid and {} invalid certs",
152 valid_count, invalid_count
153 );
154155 (valid_count, invalid_count)
156 }
157158fn add_internal(&mut self, der: &[u8]) -> Result<(), Error> {
159let ta = webpki::TrustAnchor::try_from_cert_der(der)
160 .map_err(|_| Error::InvalidCertificate(CertificateError::BadEncoding))?;
161self.roots
162 .push(OwnedTrustAnchor::from_subject_spki_name_constraints(
163 ta.subject,
164 ta.spki,
165 ta.name_constraints,
166 ));
167Ok(())
168 }
169}
170171mod tests {
172#[test]
173fn ownedtrustanchor_subject_is_correctly_encoding_dn() {
174let subject = b"subject".to_owned();
175let ota = super::OwnedTrustAnchor::from_subject_spki_name_constraints(
176 subject,
177b"".to_owned(),
178None::<Vec<u8>>,
179 );
180let expected_prefix = vec![ring::io::der::Tag::Sequence as u8, subject.len() as u8];
181assert_eq!(
182 ota.subject().as_ref(),
183 [expected_prefix, subject.to_vec()].concat()
184 );
185 }
186}