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#[derive(Clone)]
14pub struct RootCertStore {
15 pub roots: Vec<TrustAnchor<'static>>,
17}
18
19impl RootCertStore {
20 pub fn empty() -> Self {
22 Self { roots: Vec::new() }
23 }
24
25 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 = "log"), 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 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 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 pub fn is_empty(&self) -> bool {
95 self.len() == 0
96 }
97
98 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}