use crate::der::{self, CONSTRUCTED, CONTEXT_SPECIFIC, DerIterator, FromDer};
use crate::error::{DerTypeId, Error};
use crate::subject_name::GeneralName;
pub(crate) struct Extension<'a> {
pub(crate) critical: bool,
pub(crate) id: untrusted::Input<'a>,
pub(crate) value: untrusted::Input<'a>,
}
impl Extension<'_> {
pub(crate) fn unsupported(&self) -> Result<(), Error> {
match self.critical {
true => Err(Error::UnsupportedCriticalExtension),
false => Ok(()),
}
}
}
impl<'a> FromDer<'a> for Extension<'a> {
fn from_der(reader: &mut untrusted::Reader<'a>) -> Result<Self, Error> {
let id = der::expect_tag(reader, der::Tag::OID)?;
let critical = bool::from_der(reader)?;
let value = der::expect_tag(reader, der::Tag::OctetString)?;
Ok(Extension {
id,
critical,
value,
})
}
const TYPE_ID: DerTypeId = DerTypeId::Extension;
}
pub(crate) fn set_extension_once<T>(
destination: &mut Option<T>,
parser: impl Fn() -> Result<T, Error>,
) -> Result<(), Error> {
match destination {
Some(..) => Err(Error::ExtensionValueInvalid),
None => {
*destination = Some(parser()?);
Ok(())
}
}
}
pub(crate) fn remember_extension(
extension: &Extension<'_>,
mut handler: impl FnMut(u8) -> Result<(), Error>,
) -> Result<(), Error> {
static ID_CE: [u8; 2] = oid![2, 5, 29];
if extension.id.len() != ID_CE.len() + 1
|| !extension.id.as_slice_less_safe().starts_with(&ID_CE)
{
return extension.unsupported();
}
let last_octet = *extension.id.as_slice_less_safe().last().unwrap();
handler(last_octet)
}
pub(crate) enum DistributionPointName<'a> {
NameRelativeToCrlIssuer,
FullName(DerIterator<'a, GeneralName<'a>>),
}
impl<'a> FromDer<'a> for DistributionPointName<'a> {
fn from_der(reader: &mut untrusted::Reader<'a>) -> Result<Self, Error> {
const FULL_NAME_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED;
const NAME_RELATIVE_TO_CRL_ISSUER_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED | 1;
let (tag, value) = der::read_tag_and_get_value(reader)?;
match tag {
FULL_NAME_TAG => Ok(DistributionPointName::FullName(DerIterator::new(value))),
NAME_RELATIVE_TO_CRL_ISSUER_TAG => Ok(DistributionPointName::NameRelativeToCrlIssuer),
_ => Err(Error::BadDer),
}
}
const TYPE_ID: DerTypeId = DerTypeId::DistributionPointName;
}