use super::PublicKeyInfo;
use crate::algorithm::Producer;
use crate::algorithm::dstu4145::{self, Octets, Parameters, Profile, parameters};
use crate::error::Located;
use crate::{Error, ErrorCode, Result};
use structured_asn1::memory::{Execution, Work};
use structured_asn1::{Element, Encoding, ScopedReader, Tag, universal};
const FIELD: &str = "subjectPublicKey.dstu4145";
#[derive(Debug, Clone, Copy)]
pub struct PublicKey<'a> {
profile: Profile,
parameters: Option<Parameters<'a>>,
element: Element<'a>,
point: Octets<'a>,
producer: Producer<'a>,
}
impl<'a> PublicKey<'a> {
#[must_use]
pub const fn profile(self) -> Profile {
self.profile
}
#[must_use]
pub const fn parameters(self) -> Option<Parameters<'a>> {
self.parameters
}
#[must_use]
pub const fn element(self) -> Element<'a> {
self.element
}
#[must_use]
pub const fn point(self) -> Octets<'a> {
self.point
}
#[must_use]
pub fn degree(self) -> Option<u32> {
self.parameters.and_then(|p| p.curve().degree())
}
#[must_use]
pub fn execution_in<'q, W: Work>(&self, current: &'q W) -> Execution<'q>
where
'a: 'q,
{
self.producer.execution_in(current)
}
}
pub fn read<'a, W: Work>(info: PublicKeyInfo<'a>, current: &W) -> Result<PublicKey<'a>> {
let identifier = info.algorithm();
let profile = dstu4145::identify(identifier, current)?
.ok_or_else(|| Error::new(ErrorCode::UnexpectedField, FIELD, identifier.offset()))?;
let parameters = parameters::read_known(identifier, profile, current)?;
let bits = info.whole_octets(FIELD)?;
let (reader, element) = identifier
.nested(bits, info.key_offset())
.open(current, FIELD)?;
let degree = parameters.and_then(|p| p.curve().degree());
let (element, point) = if reader.encoding().is_der() {
point(&reader, element, degree, profile)?
} else {
let mut strict = reader.reread(&element, Encoding::Der).field(FIELD)?;
let written = strict
.next_element()
.field(FIELD)?
.ok_or_else(|| Error::new(ErrorCode::MissingField, FIELD, strict.offset()))?;
point(&strict, written, degree, profile)?
};
Ok(PublicKey {
profile,
parameters,
element,
point,
producer: identifier.execution_origin(),
})
}
fn point<'a>(
reader: &ScopedReader<'a, '_>,
element: Element<'a>,
degree: Option<u32>,
profile: Profile,
) -> Result<(Element<'a>, Octets<'a>)> {
let point = if let Some(degree) = degree {
parameters::field_octets(reader, element, degree, profile.byte_order())
.map_err(|error| Error::new(error.code(), FIELD, error.offset()))?
} else {
if element.tag() != Tag::primitive(universal::OCTET_STRING) {
return Err(Error::new(
ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
FIELD,
element.span().start,
));
}
Octets::new(
element.contents(),
profile.byte_order(),
element.contents_span().start,
)
};
Ok((element, point))
}