mirror of https://github.com/ctz/rustls
146 lines
4.6 KiB
Rust
146 lines
4.6 KiB
Rust
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 FromIterator<TrustAnchor<'static>> for RootCertStore {
|
|
fn from_iter<T: IntoIterator<Item = TrustAnchor<'static>>>(iter: T) -> Self {
|
|
Self {
|
|
roots: iter.into_iter().collect(),
|
|
}
|
|
}
|
|
}
|
|
|
|
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 ta = TrustAnchor {
|
|
subject: Der::from_slice(&[]),
|
|
subject_public_key_info: Der::from_slice(&[]),
|
|
name_constraints: None,
|
|
};
|
|
let store = RootCertStore::from_iter(iter::repeat(ta).take(138));
|
|
|
|
assert_eq!(
|
|
format!("{:?}", store),
|
|
"RootCertStore { roots: \"(138 roots)\" }"
|
|
);
|
|
}
|