use crate::algorithm::dstu4145::{ByteOrder, Octets};
use crate::error::Located;
use crate::{Error, ErrorCode, Result};
use structured_asn1::{Element, Encoding, ScopedReader, Tag, universal};
#[derive(Debug, Clone, Copy)]
pub struct Value<'a> {
element: Element<'a>,
r: Octets<'a>,
s: Octets<'a>,
}
impl<'a> Value<'a> {
pub fn read(
reader: &mut ScopedReader<'a, '_>,
byte_order: ByteOrder,
order_bits: u32,
field: &'static str,
) -> Result<Self> {
let element = reader
.next_element()
.field(field)?
.ok_or_else(|| Error::new(ErrorCode::MissingField, field, reader.offset()))?;
let value = Self::read_element(reader, &element, byte_order, order_bits, field)?;
if !reader.is_empty() {
return Err(Error::new(ErrorCode::TrailingData, field, reader.offset()));
}
Ok(value)
}
#[must_use]
pub const fn element(self) -> Element<'a> {
self.element
}
#[must_use]
pub const fn r(self) -> Octets<'a> {
self.r
}
#[must_use]
pub const fn s(self) -> Octets<'a> {
self.s
}
pub fn read_element(
parent: &ScopedReader<'a, '_>,
element: &Element<'a>,
byte_order: ByteOrder,
order_bits: u32,
field: &'static str,
) -> Result<Self> {
if parent.encoding().is_der() {
return Self::fields(parent, *element, byte_order, order_bits, field);
}
let mut strict = parent.reread(element, Encoding::Der).field(field)?;
let written = strict
.next_element()
.field(field)?
.ok_or_else(|| Error::new(ErrorCode::MissingField, field, strict.offset()))?;
Self::fields(&strict, written, byte_order, order_bits, field)
}
fn fields(
parent: &ScopedReader<'a, '_>,
element: Element<'a>,
byte_order: ByteOrder,
order_bits: u32,
field: &'static str,
) -> Result<Self> {
parent.charge(1).field(field)?;
if element.tag() != Tag::primitive(universal::OCTET_STRING) {
return Err(Error::new(
ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
field,
element.span().start,
));
}
let bytes = element.contents();
let width = u64::from(order_bits).div_ceil(8);
if order_bits == 0 || bytes.len() as u64 != width * 2 {
return Err(Error::new(
ErrorCode::MalformedValue,
field,
element.span().start,
));
}
let half = bytes.len() / 2;
let (first, last) = bytes.split_at(half);
let at = element.contents_span().start;
let first = Octets::new(first, byte_order, at);
let last = Octets::new(last, byte_order, at + half as u64);
let (r, s) = match byte_order {
ByteOrder::LittleEndian => (first, last),
ByteOrder::BigEndian => (last, first),
};
Ok(Self { element, r, s })
}
}