use crate::{ Asn1DerError, Source, Sink, error::ErrorChain };
pub mod length {
use crate::{ Asn1DerError, Source, Sink, rust::mem };
use crate::error::ErrorChain;
const SIZE: usize = mem::size_of::<usize>();
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
#[cfg_attr(feature = "no_panic", inline(always))]
pub fn decode<S: Source>(source: &mut S) -> Result<Option<usize>, Asn1DerError> {
let first = match source.read() {
Ok(first) => first,
Err(_) => return Ok(None)
};
match first as usize {
len if len < 0b1000_0000 => Ok(Some(len)),
size if size & 0b0111_1111 > SIZE =>
Err(eunsupported!("The object length is greater than `usize::max_value()`")),
size => {
let skip = SIZE - (size & 0b0111_1111);
let mut buf = [0u8; SIZE];
for target in buf.iter_mut().skip(skip) {
*target = match source.read() {
Ok(next) => next,
Err(_) => return Ok(None)
};
}
match usize::from_be_bytes(buf) {
len if len < 0b1000_0000 => Err(einval!("Encountered complex length < 128"))?,
len => Ok(Some(len))
}
}
}
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
#[cfg_attr(feature = "no_panic", inline(always))]
pub fn encode<S: Sink>(len: usize, sink: &mut S) -> Result<(), Asn1DerError> {
match len {
len if len < 128 => sink.write(len as u8).propagate(e!("Failed to write length byte")),
len => {
let size = SIZE.saturating_sub(len.leading_zeros() as usize / 8);
let skip = SIZE.saturating_sub(size);
sink.write(0x80 | size as u8).propagate(e!("Failed to write length byte"))?;
len.to_be_bytes().iter().skip(skip).try_for_each(|b| {
sink.write(*b).propagate(e!("Failed to write length byte"))
})
}
}
}
}
#[derive(Copy, Clone)]
pub struct DerObject<'a> {
raw: &'a[u8],
header: &'a[u8],
tag: u8,
value: &'a[u8]
}
impl<'a> DerObject<'a> {
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn new<S: Sink + Into<&'a[u8]>>(tag: u8, value: &[u8], sink: S)
-> Result<Self, Asn1DerError>
{
Self::new_from_source(tag, value.len(), &mut value.iter(), sink)
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn new_from_source<A: Source, B: Sink + Into<&'a[u8]>>(tag: u8, len: usize, value: &mut A,
mut sink: B) -> Result<Self, Asn1DerError>
{
Self::write(tag, len, value, &mut sink).propagate(e!("Failed to construct boolean"))?;
DerObject::decode(sink.into()).propagate(e!("Failed to load constructed object"))
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn decode(raw: &'a[u8]) -> Result<Self, Asn1DerError> {
Self::decode_at(raw, 0)
}
#[doc(hidden)]
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn decode_at(raw: &'a[u8], header_start: usize) -> Result<Self, Asn1DerError> {
let mut value_start = header_start;
let mut iter = raw.iter().skip(header_start).counting_source(&mut value_start);
let tag = iter.read().propagate(e!("Failed to read tag"))?;
let len = length::decode(&mut iter).propagate(e!("Failed to decode length"))?
.ok_or(eio!("Truncated length"))?;
let value_end = match value_start.checked_add(len) {
Some(value_end) => value_end,
None => Err(eunsupported!("The object bounds would exceed `usize::max_value()`"))?
};
let header = match raw.len() {
len if len >= value_start => &raw[..value_start],
_ => Err(eio!("The object is truncated"))?
};
let header = match header.len() {
len if len >= header_start => &header[header_start..],
_ => Err(eio!("The object is truncated"))?
};
let value = match raw.len() {
len if len >= value_end => &raw[..value_end],
_ => Err(eio!("The object is truncated"))?
};
let value = match value.len() {
len if len >= value_start => &value[value_start..],
_ => Err(eio!("The object is truncated"))?
};
Ok(Self{ raw, header, tag, value })
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn decode_from_source<A: Source, B: Sink + Into<&'a[u8]>>(source: &mut A, mut sink: B)
-> Result<Self, Asn1DerError>
{
let mut source = source.copying_source(&mut sink);
let _ = source.copy_next().propagate(e!("Failed to read tag"))?;
let len = length::decode(&mut source).propagate(e!("Failed to decode length"))?
.ok_or(eio!("Truncated length"))?;
source.copy_n(len).propagate(e!("Failed to copy object value"))?;
Self::decode(sink.into()).propagate(e!("Failed to decode object"))
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn raw(self) -> &'a[u8] {
self.raw
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn header(self) -> &'a[u8] {
self.header
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn tag(self) -> u8 {
self.tag
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn value(self) -> &'a[u8] {
self.value
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn encode<U: Sink>(&self, sink: &mut U) -> Result<(), Asn1DerError> {
Self::write(self.tag, self.value.len(), &mut self.value.iter(), sink)
.propagate(e!("Failed to write DER object"))
}
#[cfg_attr(feature = "no_panic", no_panic::no_panic)]
pub fn write<A: Source, B: Sink>(tag: u8, len: usize, value: &mut A, sink: &mut B)
-> Result<(), Asn1DerError>
{
sink.write(tag).propagate(e!("Failed to write tag"))?;
length::encode(len, sink).propagate(e!("Failed to write length"))?;
value.copying_source(sink).copy_n(len).propagate(e!("Failed to write value"))
}
}