| 1 | use alloc::vec::Vec; |
| 2 | use alloc::{fmt, format}; |
| 3 | |
| 4 | use pki_types::{CertificateDer, TrustAnchor}; |
| 5 | use webpki::anchor_from_trusted_cert; |
| 6 | |
| 7 | use super::pki_error; |
| 8 | use crate::log::{debug, trace}; |
| 9 | use crate::{DistinguishedName, Error}; |
| 10 | |
| 11 | /// A container for root certificates able to provide a root-of-trust |
| 12 | /// for connection authentication. |
| 13 | #[derive (Clone)] |
| 14 | pub struct RootCertStore { |
| 15 | /// The list of roots. |
| 16 | pub roots: Vec<TrustAnchor<'static>>, |
| 17 | } |
| 18 | |
| 19 | impl 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 and {} invalid certs" , |
| 56 | valid_count, invalid_count |
| 57 | ); |
| 58 | |
| 59 | (valid_count, invalid_count) |
| 60 | } |
| 61 | |
| 62 | /// Add a single DER-encoded certificate to the store. |
| 63 | /// |
| 64 | /// This is suitable for a small set of root certificates that are expected to parse |
| 65 | /// successfully. For large collections of roots (for example from a system store) it |
| 66 | /// is expected that some of them might not be valid according to the rules rustls |
| 67 | /// implements. As long as a relatively limited number of certificates are affected, |
| 68 | /// this should not be a cause for concern. Use [`RootCertStore::add_parsable_certificates`] |
| 69 | /// in order to add as many valid roots as possible and to understand how many certificates |
| 70 | /// have been diagnosed as malformed. |
| 71 | pub fn add(&mut self, der: CertificateDer<'_>) -> Result<(), Error> { |
| 72 | self.roots.push( |
| 73 | anchor_from_trusted_cert(&der) |
| 74 | .map_err(pki_error)? |
| 75 | .to_owned(), |
| 76 | ); |
| 77 | Ok(()) |
| 78 | } |
| 79 | |
| 80 | /// Return the DER encoded [`DistinguishedName`] of each trust anchor subject in the root |
| 81 | /// cert store. |
| 82 | /// |
| 83 | /// Each [`DistinguishedName`] will be a DER-encoded X.500 distinguished name, per |
| 84 | /// [RFC 5280 A.1], including the outer `SEQUENCE`. |
| 85 | /// |
| 86 | /// [RFC 5280 A.1]: https://www.rfc-editor.org/rfc/rfc5280#appendix-A.1 |
| 87 | pub fn subjects(&self) -> Vec<DistinguishedName> { |
| 88 | self.roots |
| 89 | .iter() |
| 90 | .map(|ta| DistinguishedName::in_sequence(ta.subject.as_ref())) |
| 91 | .collect() |
| 92 | } |
| 93 | |
| 94 | /// Return true if there are no certificates. |
| 95 | pub fn is_empty(&self) -> bool { |
| 96 | self.len() == 0 |
| 97 | } |
| 98 | |
| 99 | /// Say how many certificates are in the container. |
| 100 | pub fn len(&self) -> usize { |
| 101 | self.roots.len() |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | impl FromIterator<TrustAnchor<'static>> for RootCertStore { |
| 106 | fn from_iter<T: IntoIterator<Item = TrustAnchor<'static>>>(iter: T) -> Self { |
| 107 | Self { |
| 108 | roots: iter.into_iter().collect(), |
| 109 | } |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | impl Extend<TrustAnchor<'static>> for RootCertStore { |
| 114 | fn extend<T: IntoIterator<Item = TrustAnchor<'static>>>(&mut self, iter: T) { |
| 115 | self.roots.extend(iter); |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | impl fmt::Debug for RootCertStore { |
| 120 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 121 | f&mut DebugStruct<'_, '_>.debug_struct("RootCertStore" ) |
| 122 | .field(name:"roots" , &format!("( {} roots)" , &self.roots.len())) |
| 123 | .finish() |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | #[test ] |
| 128 | fn root_cert_store_debug() { |
| 129 | use core::iter; |
| 130 | |
| 131 | use pki_types::Der; |
| 132 | |
| 133 | let ta = TrustAnchor { |
| 134 | subject: Der::from_slice(&[]), |
| 135 | subject_public_key_info: Der::from_slice(&[]), |
| 136 | name_constraints: None, |
| 137 | }; |
| 138 | let store = RootCertStore::from_iter(iter::repeat(ta).take(138)); |
| 139 | |
| 140 | assert_eq!( |
| 141 | format!("{:?}" , store), |
| 142 | "RootCertStore { roots: \"(138 roots) \" }" |
| 143 | ); |
| 144 | } |
| 145 | |