#![allow(unused)]
use std::{fmt::Debug, sync::Arc};
#[cfg(feature = "boring")]
use boring::{
ssl::SslConnectorBuilder,
x509::store::{X509Store, X509StoreBuilder},
};
#[cfg(all(feature = "rustls-tls", not(feature = "boring")))]
use rustls::RootCertStore;
#[cfg(feature = "boring")]
use super::parser::{parse_certs, parse_certs_with_stack};
use super::{
Certificate, CertificateInput,
parser::{filter_map_certs, process_certs},
};
use crate::{Error, Result};
pub struct CertStoreBuilder {
#[cfg(feature = "boring")]
builder: Result<X509StoreBuilder>,
#[cfg(all(feature = "rustls-tls", not(feature = "boring")))]
builder: Result<RootCertStore>,
#[cfg(not(any(feature = "boring", feature = "rustls-tls")))]
_marker: std::marker::PhantomData<()>,
}
impl CertStoreBuilder {
#[inline]
pub fn add_der_cert<'c, C>(self, cert: C) -> Self
where
C: Into<CertificateInput<'c>>,
{
self.parse_cert(cert, Certificate::from_der)
}
#[inline]
pub fn add_pem_cert<'c, C>(self, cert: C) -> Self
where
C: Into<CertificateInput<'c>>,
{
self.parse_cert(cert, Certificate::from_pem)
}
#[inline]
pub fn add_der_certs<'c, I>(self, certs: I) -> Self
where
I: IntoIterator,
I::Item: Into<CertificateInput<'c>>,
{
self.parse_certs(certs, Certificate::from_der)
}
#[inline]
pub fn add_pem_certs<'c, I>(self, certs: I) -> Self
where
I: IntoIterator,
I::Item: Into<CertificateInput<'c>>,
{
self.parse_certs(certs, Certificate::from_pem)
}
pub fn add_stack_pem_certs<C>(mut self, certs: C) -> Self
where
C: AsRef<[u8]>,
{
#[cfg(any(feature = "boring", feature = "rustls-tls"))]
if let Ok(ref mut builder) = self.builder {
#[cfg(feature = "boring")]
{
let result = Certificate::stack_from_pem(certs.as_ref())
.and_then(|certs| process_certs(certs.into_iter(), builder));
if let Err(err) = result {
self.builder = Err(err);
}
}
#[cfg(all(feature = "rustls-tls", not(feature = "boring")))]
{
let result = Certificate::stack_from_pem(certs.as_ref())
.and_then(|certs| process_certs(certs.into_iter(), builder));
if let Err(err) = result {
self.builder = Err(err);
}
}
}
self
}
pub fn set_default_paths(mut self) -> Self {
#[cfg(any(feature = "boring", feature = "rustls-tls"))]
if let Ok(ref mut builder) = self.builder {
#[cfg(feature = "boring")]
if let Err(err) = builder.set_default_paths() {
self.builder = Err(Error::tls(err));
}
#[cfg(all(feature = "rustls-tls", not(feature = "boring")))]
{
builder.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
}
}
self
}
#[inline]
pub fn build(self) -> Result<CertStore> {
#[cfg(feature = "boring")]
return self
.builder
.map(X509StoreBuilder::build)
.map(Arc::new)
.map(CertStore);
#[cfg(all(feature = "rustls-tls", not(feature = "boring")))]
return self.builder.map(Arc::new).map(CertStore);
#[cfg(not(any(feature = "boring", feature = "rustls-tls")))]
return Ok(CertStore(std::marker::PhantomData));
}
fn parse_cert<'c, C, F>(mut self, cert: C, parser: F) -> Self
where
C: Into<CertificateInput<'c>>,
F: Fn(&'c [u8]) -> Result<Certificate>,
{
#[cfg(any(feature = "boring", feature = "rustls-tls"))]
if let Ok(ref mut builder) = self.builder {
let cert = cert.into().with_parser(parser);
let result = cert.and_then(|cert| process_certs(std::iter::once(cert), builder));
if let Err(err) = result {
self.builder = Err(err);
}
}
self
}
fn parse_certs<'c, I, F>(mut self, certs: I, parser: F) -> Self
where
I: IntoIterator,
I::Item: Into<CertificateInput<'c>>,
F: Fn(&'c [u8]) -> Result<Certificate>,
{
#[cfg(any(feature = "boring", feature = "rustls-tls"))]
if let Ok(ref mut builder) = self.builder {
let certs = certs
.into_iter()
.map(|cert| cert.into().with_parser(&parser));
let certs_iter = filter_map_certs(certs);
let result = process_certs(certs_iter, builder);
if let Err(err) = result {
self.builder = Err(err);
}
}
self
}
}
impl CertStore {
pub fn builder() -> CertStoreBuilder {
#[cfg(feature = "boring")]
let builder = X509StoreBuilder::new().map_err(Error::tls);
#[cfg(all(feature = "rustls-tls", not(feature = "boring")))]
let builder = Ok(RootCertStore::empty());
#[cfg(any(feature = "boring", feature = "rustls-tls"))]
return CertStoreBuilder { builder };
#[cfg(not(any(feature = "boring", feature = "rustls-tls")))]
return CertStoreBuilder {
_marker: std::marker::PhantomData,
};
}
pub fn from_der_certs<'a, I>(certs: I) -> Result<Self>
where
I: IntoIterator,
I::Item: Into<CertificateInput<'a>>,
{
CertStore::builder().add_der_certs(certs).build()
}
}
impl Default for CertStore {
fn default() -> Self {
CertStore::builder().set_default_paths().build().unwrap()
}
}
#[derive(Clone)]
pub struct CertStore(
#[cfg(feature = "boring")] pub(crate) Arc<X509Store>,
#[cfg(all(feature = "rustls-tls", not(feature = "boring")))] pub(crate) Arc<RootCertStore>,
#[cfg(not(any(feature = "boring", feature = "rustls-tls")))]
pub(crate) std::marker::PhantomData<()>,
);
impl Debug for CertStore {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CertStore").finish()
}
}