Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion der/src/asn1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub use self::{
octet_string::OctetString,
optional::OptionalRef,
printable_string::PrintableString,
sequence::Sequence,
sequence::{Sequence, SequenceRef},
sequence_of::{SequenceOf, SequenceOfIter},
set_of::{SetOf, SetOfIter},
utc_time::UtcTime,
Expand Down
49 changes: 48 additions & 1 deletion der/src/asn1/sequence.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
//! The [`Sequence`] trait simplifies writing decoders/encoders which map ASN.1
//! `SEQUENCE`s to Rust structs.

use crate::{Decodable, Encodable, EncodeValue, Encoder, FixedTag, Length, Result, Tag};
use crate::{
ByteSlice, Decodable, DecodeValue, Decoder, Encodable, EncodeValue, Encoder, FixedTag, Length,
Result, Tag,
};

/// ASN.1 `SEQUENCE` trait.
///
Expand Down Expand Up @@ -48,3 +51,47 @@ where
{
const TAG: Tag = Tag::Sequence;
}

/// The [`SequenceRef`] type provides raw access to the octets which comprise a
/// DER-encoded `SEQUENCE`.
pub struct SequenceRef<'a> {
/// Body of the `SEQUENCE`.
body: ByteSlice<'a>,

/// Offset location in the outer document where this `SEQUENCE` begins.
offset: Length,
}

impl<'a> SequenceRef<'a> {
/// Decode the body of this sequence.
pub fn decode_body<F, T>(&self, f: F) -> Result<T>
where
F: FnOnce(&mut Decoder<'a>) -> Result<T>,
{
let mut nested_decoder = Decoder::new_with_offset(self.body, self.offset);
let result = f(&mut nested_decoder)?;
nested_decoder.finish(result)
}
}

impl<'a> DecodeValue<'a> for SequenceRef<'a> {
fn decode_value(decoder: &mut Decoder<'a>, length: Length) -> Result<Self> {
let offset = decoder.position();
let body = ByteSlice::decode_value(decoder, length)?;
Ok(Self { body, offset })
}
}

impl EncodeValue for SequenceRef<'_> {
fn value_len(&self) -> Result<Length> {
Ok(self.body.len())
}

fn encode_value(&self, encoder: &mut Encoder<'_>) -> Result<()> {
self.body.encode_value(encoder)
}
}

impl<'a> FixedTag for SequenceRef<'a> {
const TAG: Tag = Tag::Sequence;
}
58 changes: 21 additions & 37 deletions der/src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ pub struct Decoder<'a> {

/// Position within the decoded slice.
position: Length,

/// Offset where `bytes` occurs in the original ASN.1 DER document.
///
/// Used for nested decoding.
offset: Length,
}

impl<'a> Decoder<'a> {
Expand All @@ -24,9 +29,22 @@ impl<'a> Decoder<'a> {
Ok(Self {
bytes: Some(ByteSlice::new(bytes)?),
position: Length::ZERO,
offset: Length::ZERO,
})
}

/// Create a new decoder where `bytes` begins at a specified offset within
/// an original ASN.1 DER document.
///
/// This is used for calculating positions when decoding nested documents.
pub(crate) fn new_with_offset(bytes: ByteSlice<'a>, offset: Length) -> Self {
Self {
bytes: Some(bytes),
position: Length::ZERO,
offset,
}
}

/// Decode a value which impls the [`Decodable`] trait.
pub fn decode<T: Decodable<'a>>(&mut self) -> Result<T> {
if self.is_failed() {
Expand Down Expand Up @@ -58,7 +76,8 @@ impl<'a> Decoder<'a> {

/// Get the position within the buffer.
pub fn position(&self) -> Length {
self.position
// TODO(tarcieri): avoid potential panic here
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can probably be addressed by incrementing both position and offset when data is read. This was a quick workaround to get everything initially working.

(self.position + self.offset).expect("overflow")
}

/// Peek at the next byte in the decoder without modifying the cursor.
Expand Down Expand Up @@ -231,9 +250,7 @@ impl<'a> Decoder<'a> {
where
F: FnOnce(&mut Decoder<'a>) -> Result<T>,
{
Tag::try_from(self.byte()?)?.assert_eq(Tag::Sequence)?;
let len = Length::decode(self)?;
self.decode_nested(len, f)
SequenceRef::decode(self)?.decode_body(f)
}

/// Decode a single byte, updating the internal cursor.
Expand Down Expand Up @@ -295,39 +312,6 @@ impl<'a> Decoder<'a> {
self.remaining()?.len().try_into()
}

/// Create a nested decoder which operates over the provided [`Length`].
///
/// The nested decoder is passed to the provided callback function which is
/// expected to decode a value of type `T` with it.
fn decode_nested<F, T>(&mut self, length: Length, f: F) -> Result<T>
where
F: FnOnce(&mut Self) -> Result<T>,
{
let start_pos = self.position();
let end_pos = (start_pos + length)?;
let bytes = match self.bytes {
Some(slice) => {
slice
.as_bytes()
.get(..end_pos.try_into()?)
.ok_or(ErrorKind::Incomplete {
expected_len: end_pos,
actual_len: self.input_len()?,
})?
}
None => return Err(self.error(ErrorKind::Failed)),
};

let mut nested_decoder = Self {
bytes: Some(ByteSlice::new(bytes)?),
position: start_pos,
};

self.position = end_pos;
let result = f(&mut nested_decoder)?;
nested_decoder.finish(result)
}

/// Obtain the remaining bytes in this decoder from the current cursor
/// position.
fn remaining(&self) -> Result<&'a [u8]> {
Expand Down