use super::{end, names, sequence, tag};
use crate::attribute::Attribute;
use crate::signer::required;
use crate::{Error, ErrorCode, Result};
use structured_asn1::memory::{OwnedVec, Work};
use structured_asn1::{Element, Encoding, Oid, ScopedReader, Tag, universal};
use structured_pkix::general_name::GeneralName;
const FIELD: &str = "attributeCertificate.ietfAttrSyntax";
pub const CHARGING_IDENTITY: Oid<'static> = Oid::from_bytes(&[43, 6, 1, 5, 5, 7, 10, 3]);
pub const GROUP: Oid<'static> = Oid::from_bytes(&[43, 6, 1, 5, 5, 7, 10, 4]);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Choice {
Octets,
Oid,
Utf8,
}
#[derive(Debug, Clone, Copy)]
pub enum Value<'a> {
Octets(&'a [u8]),
Oid(Oid<'a>),
Utf8(&'a str),
}
impl Value<'_> {
#[must_use]
pub fn choice(self) -> Choice {
match self {
Self::Octets(_) => Choice::Octets,
Self::Oid(_) => Choice::Oid,
Self::Utf8(_) => Choice::Utf8,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Member<'a> {
pub element: Element<'a>,
pub value: Value<'a>,
}
#[derive(Debug)]
pub struct IetfAttrSyntax<'a> {
element: Element<'a>,
authority: Option<OwnedVec<GeneralName<'a>>>,
authority_element: Option<Element<'a>>,
values: OwnedVec<Member<'a>>,
choice: Option<Choice>,
}
impl<'a> IetfAttrSyntax<'a> {
pub fn read(parent: &mut ScopedReader<'a, '_>) -> Result<Self> {
let element = required(parent, FIELD)?;
let reading = Self::read_element(parent, &element)?;
end(parent, FIELD)?;
Ok(reading)
}
pub fn read_element(parent: &ScopedReader<'a, '_>, element: &Element<'a>) -> Result<Self> {
let mut der = parent
.reread(element, Encoding::Der)
.map_err(|e| Error::encoding(e, FIELD))?;
let element = required(&mut der, FIELD)?;
tag(&element, sequence(), FIELD)?;
end(&der, FIELD)?;
let mut inside = der.enter(&element).map_err(|e| Error::encoding(e, FIELD))?;
let mut first = required(&mut inside, FIELD)?;
let (authority, authority_element) = if first.tag() == Tag::context(true, 0) {
let authority = names(&inside, &first, FIELD)?;
let encoded = first;
first = required(&mut inside, FIELD)?;
(Some(authority), Some(encoded))
} else {
(None, None)
};
tag(&first, sequence(), FIELD)?;
end(&inside, FIELD)?;
let mut members = inside
.enter(&first)
.map_err(|e| Error::encoding(e, FIELD))?;
let execution = inside.execution();
let mut values = execution.vector();
let mut choice = None;
while let Some(encoded) = members
.next_element()
.map_err(|e| Error::encoding(e, FIELD))?
{
let selected = match encoded.tag() {
t if t == Tag::primitive(universal::OCTET_STRING) => Choice::Octets,
t if t == Tag::primitive(universal::OID) => Choice::Oid,
t if t == Tag::primitive(universal::UTF8_STRING) => Choice::Utf8,
_ => {
return Err(Error::schema(
ErrorCode::UnexpectedTag,
FIELD,
encoded.span().start,
));
}
};
if let Some(previous) = choice
&& previous != selected
{
return Err(Error::schema(
ErrorCode::AttributeSyntax,
FIELD,
encoded.span().start,
));
}
let value = match selected {
Choice::Octets => Value::Octets(encoded.contents()),
Choice::Oid => Value::Oid(
members
.oid(&encoded)
.map_err(|e| Error::encoding(e, FIELD))?,
),
Choice::Utf8 => {
members
.charge(encoded.contents().len() as u64)
.map_err(|e| Error::encoding(e, FIELD))?;
Value::Utf8(core::str::from_utf8(encoded.contents()).map_err(|e| {
Error::schema(
ErrorCode::MalformedValue,
FIELD,
encoded.contents_span().start + e.valid_up_to() as u64,
)
})?)
}
};
values
.try_push(Member {
element: encoded,
value,
})
.map_err(|e| Error::resource(e, FIELD, encoded.span().start))?;
choice = Some(selected);
}
Ok(Self {
element,
authority,
authority_element,
values: values.into_owned(),
choice,
})
}
pub fn read_attribute<W: Work>(attribute: &Attribute<'a>, work: &W) -> Result<Self> {
let execution = attribute.query_in(work);
execution
.charge_work(17)
.map_err(|e| Error::resource(e, FIELD, attribute.span().start))?;
if attribute.kind() != GROUP && attribute.kind() != CHARGING_IDENTITY {
return Err(Error::schema(
ErrorCode::UnexpectedContentType,
FIELD,
attribute.span().start,
));
}
if attribute.values().len() != 1 {
return Err(Error::schema(
ErrorCode::AttributeCardinality,
FIELD,
attribute.span().start,
));
}
let mut reader = attribute
.value_reader_scoped(0, &execution, FIELD)?
.ok_or_else(|| {
Error::schema(
ErrorCode::AttributeCardinality,
FIELD,
attribute.span().start,
)
})?;
Self::read(&mut reader)
}
#[must_use]
pub fn element(&self) -> Element<'a> {
self.element
}
#[must_use]
pub fn authority(&self) -> Option<&[GeneralName<'a>]> {
self.authority.as_deref()
}
#[must_use]
pub fn authority_element(&self) -> Option<Element<'a>> {
self.authority_element
}
#[must_use]
pub fn values(&self) -> &[Member<'a>] {
&self.values
}
#[must_use]
pub fn choice(&self) -> Option<Choice> {
self.choice
}
}