use std::sync::Arc;
use btls::x509::store::{X509Store, X509StoreBuilder};
use super::{
Certificate, CertificateInput,
parse::{filter_map_certs, parse_certs, parse_certs_with_stack, process_certs},
};
use crate::{Error, Result};
pub struct CertStoreBuilder {
builder: Result<X509StoreBuilder>,
}
impl CertStoreBuilder {
fn parse_cert<'c, C, P>(mut self, cert: C, parser: P) -> Self
where
C: Into<CertificateInput<'c>>,
P: Fn(&'c [u8]) -> Result<Certificate>,
{
if let Ok(ref mut builder) = self.builder {
let input = cert.into();
let result = input
.with_parser(parser)
.and_then(|cert| builder.add_cert(cert.0).map_err(Error::tls));
if let Err(err) = result {
self.builder = Err(err);
}
}
self
}
fn parse_certs<'c, I>(mut self, certs: I, parser: fn(&'c [u8]) -> Result<Certificate>) -> Self
where
I: IntoIterator,
I::Item: Into<CertificateInput<'c>>,
{
if let Ok(ref mut builder) = self.builder {
let certs = filter_map_certs(certs, parser);
if let Err(err) = process_certs(certs, builder) {
self.builder = Err(err);
}
}
self
}
#[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]>,
{
if let Ok(ref mut builder) = self.builder {
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 {
if let Ok(ref mut builder) = self.builder {
if let Err(err) = builder.set_default_paths() {
self.builder = Err(Error::tls(err));
}
}
self
}
#[inline]
pub fn build(self) -> Result<CertStore> {
self.builder
.map(X509StoreBuilder::build)
.map(Arc::new)
.map(CertStore)
}
}
#[derive(Clone)]
pub struct CertStore(pub(in crate::tls) Arc<X509Store>);
impl CertStore {
#[inline]
pub fn builder() -> CertStoreBuilder {
CertStoreBuilder {
builder: X509StoreBuilder::new().map_err(Error::builder),
}
}
#[inline]
pub fn from_der_certs<'c, C>(certs: C) -> Result<CertStore>
where
C: IntoIterator,
C::Item: Into<CertificateInput<'c>>,
{
parse_certs(certs, Certificate::from_der)
.map(Arc::new)
.map(CertStore)
}
#[inline]
pub fn from_pem_certs<'c, C>(certs: C) -> Result<CertStore>
where
C: IntoIterator,
C::Item: Into<CertificateInput<'c>>,
{
parse_certs(certs, Certificate::from_pem)
.map(Arc::new)
.map(CertStore)
}
#[inline]
pub fn from_pem_stack<C>(certs: C) -> Result<CertStore>
where
C: AsRef<[u8]>,
{
parse_certs_with_stack(certs, Certificate::stack_from_pem)
.map(Arc::new)
.map(CertStore)
}
}