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)\" }"
);
}