use super::same_oid;
use crate::error::{Error, ErrorCode, Located, Result};
use crate::path::WorkingKey;
use structured_asn1::memory::Work;
use structured_asn1::{Element, Encoding, Integer, Oid, ScopedReader, Tag, universal};
const OID: Oid<'static> = Oid::from_bytes(&[0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01]);
const FIELD: &str = "subjectPublicKey.dsa";
const PARAMETERS: &str = "subjectPublicKeyInfo.algorithm.parameters";
#[derive(Debug, Clone, Copy)]
pub struct Component<'a> {
element: Element<'a>,
integer: Integer<'a>,
}
impl<'a> Component<'a> {
#[must_use]
pub fn as_bytes(&self) -> &'a [u8] {
match self.integer.as_bytes() {
[0, rest @ ..] if !rest.is_empty() => rest,
bytes => bytes,
}
}
#[must_use]
pub fn integer(&self) -> Integer<'a> {
self.integer
}
#[must_use]
pub fn element(&self) -> Element<'a> {
self.element
}
}
#[derive(Debug, Clone, Copy)]
pub struct Parameters<'a> {
element: Element<'a>,
p: Component<'a>,
q: Component<'a>,
g: Component<'a>,
inherited: bool,
}
impl<'a> Parameters<'a> {
#[must_use]
pub fn p(&self) -> &Component<'a> {
&self.p
}
#[must_use]
pub fn q(&self) -> &Component<'a> {
&self.q
}
#[must_use]
pub fn g(&self) -> &Component<'a> {
&self.g
}
#[must_use]
pub fn element(&self) -> Element<'a> {
self.element
}
#[must_use]
pub fn is_inherited(&self) -> bool {
self.inherited
}
}
#[derive(Debug, Clone, Copy)]
pub struct PublicKey<'a> {
y: Component<'a>,
parameters: Option<Parameters<'a>>,
}
impl<'a> PublicKey<'a> {
#[must_use]
pub fn y(&self) -> &Component<'a> {
&self.y
}
#[must_use]
pub fn parameters(&self) -> Option<&Parameters<'a>> {
self.parameters.as_ref()
}
}
pub fn read<'a, W: Work>(key: WorkingKey<'a>, execution: &W) -> Result<PublicKey<'a>> {
let info = key.key();
let own = info.algorithm();
if !same_oid(own.algorithm(), OID, execution, FIELD, own.offset())? {
return Err(Error::new(ErrorCode::UnexpectedField, FIELD, own.offset()));
}
if let Some(source) = own.parameters_nested()
&& own.has_null_parameter()
{
let (_, written) = source.open(execution, PARAMETERS)?;
return Err(Error::new(
ErrorCode::MalformedValue,
PARAMETERS,
written.span().start,
));
}
let parameters = if let Some(source) = key.parameter_source() {
let (reader, element) = source.open(execution, PARAMETERS)?;
if element.tag() != Tag::constructed(universal::SEQUENCE) {
return Err(Error::new(
ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
PARAMETERS,
element.span().start,
));
}
let mut fields = reader.enter(&element).field(PARAMETERS)?;
let p = component(&mut fields, PARAMETERS)?;
let q = component(&mut fields, PARAMETERS)?;
let g = component(&mut fields, PARAMETERS)?;
if !fields.is_empty() {
return Err(Error::new(
ErrorCode::TrailingData,
PARAMETERS,
fields.offset(),
));
}
Some(Parameters {
element,
p,
q,
g,
inherited: own.parameters().is_none(),
})
} else {
None
};
let octets = info.whole_octets(FIELD)?;
let (reader, element) = own
.nested(octets, info.key_offset())
.open(execution, FIELD)?;
let y = if reader.encoding().is_der() {
unsigned(&reader, element, FIELD)?
} else {
let mut strict = reader.reread(&element, Encoding::Der).field(FIELD)?;
component(&mut strict, FIELD)?
};
Ok(PublicKey { y, parameters })
}
fn component<'a>(reader: &mut ScopedReader<'a, '_>, field: &'static str) -> Result<Component<'a>> {
let element = reader
.expect(Tag::primitive(universal::INTEGER))
.field(field)?;
unsigned(reader, element, field)
}
fn unsigned<'a>(
reader: &ScopedReader<'a, '_>,
element: Element<'a>,
field: &'static str,
) -> Result<Component<'a>> {
if element.tag() != Tag::primitive(universal::INTEGER) {
return Err(Error::new(
ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
field,
element.span().start,
));
}
let integer = reader.integer(&element).field(field)?;
if integer.is_negative() {
return Err(Error::new(
ErrorCode::MalformedValue,
field,
element.span().start,
));
}
Ok(Component { element, integer })
}