use crate::PolicyFailureReason;
use crate::der_parser::Oid;
use crate::policy::{PolicyEvaluationResult, ValidationPolicy};
use crate::unverified_chain::UnverifiedCertificateChain;
pub struct Tuple2<A, B> {
first: A,
second: B,
}
impl<A, B> Tuple2<A, B> {
pub fn new(first: A, second: B) -> Self {
Self { first, second }
}
}
impl<A: ValidationPolicy, B: ValidationPolicy> ValidationPolicy for Tuple2<A, B> {
fn verifying_critical_extensions(&self) -> Vec<Oid<'static>> {
let mut exts = self
.first
.verifying_critical_extensions();
exts.extend(
self.second
.verifying_critical_extensions(),
);
exts
}
fn chain_meets_policy_requirements(
&self,
chain: &UnverifiedCertificateChain<'_>,
) -> PolicyEvaluationResult {
self.first
.chain_meets_policy_requirements(chain)?;
self.second
.chain_meets_policy_requirements(chain)
}
}
pub enum Either<A, B> {
First(A),
Second(B),
}
impl<A: ValidationPolicy, B: ValidationPolicy> ValidationPolicy for Either<A, B> {
fn verifying_critical_extensions(&self) -> Vec<Oid<'static>> {
match self {
Self::First(a) => a.verifying_critical_extensions(),
Self::Second(b) => b.verifying_critical_extensions(),
}
}
fn chain_meets_policy_requirements(
&self,
chain: &UnverifiedCertificateChain<'_>,
) -> PolicyEvaluationResult {
match self {
Self::First(a) => a.chain_meets_policy_requirements(chain),
Self::Second(b) => b.chain_meets_policy_requirements(chain),
}
}
}
pub struct WrappedOptional<P> {
wrapped: Option<P>,
}
impl<P> WrappedOptional<P> {
pub fn new(wrapped: Option<P>) -> Self {
Self { wrapped }
}
}
impl<P: ValidationPolicy> ValidationPolicy for WrappedOptional<P> {
fn verifying_critical_extensions(&self) -> Vec<Oid<'static>> {
self.wrapped
.as_ref()
.map(|p| p.verifying_critical_extensions())
.unwrap_or_default()
}
fn chain_meets_policy_requirements(
&self,
chain: &UnverifiedCertificateChain<'_>,
) -> PolicyEvaluationResult {
match &self.wrapped {
Some(p) => p.chain_meets_policy_requirements(chain),
None => Ok(()),
}
}
}
#[macro_export]
macro_rules! policy {
(if ($cond:expr) { $then:expr } else { $else_:expr }; $($rest:tt)+) => {
$crate::policy_builder::Tuple2::new(
if $cond {
$crate::policy_builder::Either::First($then)
} else {
$crate::policy_builder::Either::Second($else_)
},
$crate::policy!($($rest)+),
)
};
(if ($cond:expr) { $then:expr } else { $else_:expr }) => {
if $cond {
$crate::policy_builder::Either::First($then)
} else {
$crate::policy_builder::Either::Second($else_)
}
};
(if ($cond:expr) { $body:expr }; $($rest:tt)+) => {
$crate::policy_builder::Tuple2::new(
$crate::policy_builder::WrappedOptional::new(if $cond { Some($body) } else { None }),
$crate::policy!($($rest)+),
)
};
(if ($cond:expr) { $body:expr }) => {
$crate::policy_builder::WrappedOptional::new(if $cond { Some($body) } else { None })
};
($first:expr; $($rest:tt)+) => {
$crate::policy_builder::Tuple2::new($first, $crate::policy!($($rest)+))
};
($only:expr) => {
$only
};
}
pub struct OneOfTuple2<A, B> {
first: A,
second: B,
}
impl<A, B> OneOfTuple2<A, B> {
pub fn new(first: A, second: B) -> Self {
Self { first, second }
}
}
impl<A: ValidationPolicy, B: ValidationPolicy> ValidationPolicy for OneOfTuple2<A, B> {
fn verifying_critical_extensions(&self) -> Vec<Oid<'static>> {
let first = self
.first
.verifying_critical_extensions();
let second = self
.second
.verifying_critical_extensions();
first
.into_iter()
.filter(|oid| second.contains(oid))
.collect()
}
fn chain_meets_policy_requirements(
&self,
chain: &UnverifiedCertificateChain<'_>,
) -> PolicyEvaluationResult {
match self
.first
.chain_meets_policy_requirements(chain)
{
Ok(()) => Ok(()),
Err(first_reason) => match self
.second
.chain_meets_policy_requirements(chain)
{
Ok(()) => Ok(()),
Err(second_reason) => Err(PolicyFailureReason::new(format!(
"{first_reason} and {second_reason}"
))),
},
}
}
}
pub struct OneOfWrappedOptional<P> {
wrapped: Option<P>,
}
impl<P> OneOfWrappedOptional<P> {
pub fn new(wrapped: Option<P>) -> Self {
Self { wrapped }
}
}
impl<P: ValidationPolicy> ValidationPolicy for OneOfWrappedOptional<P> {
fn verifying_critical_extensions(&self) -> Vec<Oid<'static>> {
self.wrapped
.as_ref()
.map(|p| p.verifying_critical_extensions())
.unwrap_or_default()
}
fn chain_meets_policy_requirements(
&self,
chain: &UnverifiedCertificateChain<'_>,
) -> PolicyEvaluationResult {
match &self.wrapped {
Some(p) => p.chain_meets_policy_requirements(chain),
None => Err(PolicyFailureReason::new("alternative is disabled")),
}
}
}
#[macro_export]
macro_rules! one_of {
(if ($cond:expr) { $then:expr } else { $else_:expr }; $($rest:tt)+) => {
$crate::policy_builder::OneOfTuple2::new(
if $cond {
$crate::policy_builder::Either::First($then)
} else {
$crate::policy_builder::Either::Second($else_)
},
$crate::one_of!($($rest)+),
)
};
(if ($cond:expr) { $then:expr } else { $else_:expr }) => {
if $cond {
$crate::policy_builder::Either::First($then)
} else {
$crate::policy_builder::Either::Second($else_)
}
};
(if ($cond:expr) { $body:expr }; $($rest:tt)+) => {
$crate::policy_builder::OneOfTuple2::new(
$crate::policy_builder::OneOfWrappedOptional::new(if $cond { Some($body) } else { None }),
$crate::one_of!($($rest)+),
)
};
(if ($cond:expr) { $body:expr }) => {
$crate::policy_builder::OneOfWrappedOptional::new(if $cond { Some($body) } else { None })
};
($first:expr; $($rest:tt)+) => {
$crate::policy_builder::OneOfTuple2::new($first, $crate::one_of!($($rest)+))
};
($only:expr) => {
$only
};
}