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
1 change: 1 addition & 0 deletions der/derive/src/choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ impl DeriveChoice {

impl<#lt_params> ::der::Decode<#lifetime> for #ident<#lt_params> {
fn decode(decoder: &mut ::der::Decoder<#lifetime>) -> ::der::Result<Self> {
use der::Reader as _;
match decoder.peek_tag()? {
#(#decode_body)*
actual => Err(der::ErrorKind::TagUnexpected {
Expand Down
4 changes: 2 additions & 2 deletions der/src/asn1/bit_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{
asn1::Any, ByteSlice, DecodeValue, Decoder, DerOrd, EncodeValue, Encoder, Error, ErrorKind,
FixedTag, Header, Length, Result, Tag, ValueOrd, Writer,
FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer,
};
use core::{cmp::Ordering, iter::FusedIterator};

Expand Down Expand Up @@ -122,7 +122,7 @@ impl<'a> DecodeValue<'a> for BitString<'a> {
length: (header.length - Length::ONE)?,
};

let unused_bits = decoder.byte()?;
let unused_bits = decoder.read_byte()?;
let inner = ByteSlice::decode_value(decoder, header)?;
Self::new(unused_bits, inner.as_bytes())
}
Expand Down
4 changes: 2 additions & 2 deletions der/src/asn1/boolean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{
asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, Decoder, EncodeValue, Encoder, Error,
ErrorKind, FixedTag, Header, Length, Result, Tag, Writer,
ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer,
};

/// Byte used to encode `true` in ASN.1 DER. From X.690 Section 11.1:
Expand All @@ -20,7 +20,7 @@ impl<'a> DecodeValue<'a> for bool {
return Err(decoder.error(ErrorKind::Length { tag: Self::TAG }));
}

match decoder.byte()? {
match decoder.read_byte()? {
FALSE_OCTET => Ok(false),
TRUE_OCTET => Ok(true),
_ => Err(Self::TAG.non_canonical_error()),
Expand Down
2 changes: 1 addition & 1 deletion der/src/asn1/context_specific.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{
asn1::Any, Choice, Decode, DecodeValue, Decoder, DerOrd, Encode, EncodeValue, EncodeValueRef,
Encoder, Error, Header, Length, Result, Tag, TagMode, TagNumber, Tagged, ValueOrd,
Encoder, Error, Header, Length, Reader, Result, Tag, TagMode, TagNumber, Tagged, ValueOrd,
};
use core::cmp::Ordering;

Expand Down
2 changes: 1 addition & 1 deletion der/src/asn1/optional.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! ASN.1 `OPTIONAL` as mapped to Rust's `Option` type

use crate::{Choice, Decode, Decoder, DerOrd, Encode, Encoder, Length, Result, Tag};
use crate::{Choice, Decode, Decoder, DerOrd, Encode, Encoder, Length, Reader, Result, Tag};
use core::cmp::Ordering;

impl<'a, T> Decode<'a> for Option<T>
Expand Down
2 changes: 1 addition & 1 deletion der/src/asn1/sequence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use crate::{
ByteSlice, Decode, DecodeValue, Decoder, Encode, EncodeValue, Encoder, FixedTag, Header,
Length, Result, Tag,
Length, Reader, Result, Tag,
};

/// ASN.1 `SEQUENCE` trait.
Expand Down
2 changes: 1 addition & 1 deletion der/src/asn1/sequence_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{
arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, Decoder, DerOrd, Encode, EncodeValue,
Encoder, ErrorKind, FixedTag, Header, Length, Result, Tag, ValueOrd,
Encoder, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd,
};
use core::cmp::Ordering;

Expand Down
2 changes: 1 addition & 1 deletion der/src/asn1/set_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{
arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, Decoder, DerOrd, Encode, EncodeValue,
Encoder, Error, ErrorKind, FixedTag, Header, Length, Result, Tag, ValueOrd,
Encoder, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd,
};
use core::cmp::Ordering;

Expand Down
4 changes: 2 additions & 2 deletions der/src/byte_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use crate::{
str_slice::StrSlice, DecodeValue, Decoder, DerOrd, EncodeValue, Encoder, Error, Header, Length,
Result, Writer,
Reader, Result, Writer,
};
use core::cmp::Ordering;

Expand Down Expand Up @@ -57,7 +57,7 @@ impl AsRef<[u8]> for ByteSlice<'_> {

impl<'a> DecodeValue<'a> for ByteSlice<'a> {
fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result<Self> {
decoder.bytes(header.length).and_then(Self::new)
decoder.read_slice(header.length).and_then(Self::new)
}
}

Expand Down
140 changes: 52 additions & 88 deletions der/src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{
asn1::*, ByteSlice, Choice, Decode, DecodeValue, Encode, Error, ErrorKind, FixedTag, Header,
Length, Result, Tag, TagMode, TagNumber,
Length, Reader, Result, Tag, TagMode, TagNumber,
};

/// DER decoder.
Expand Down Expand Up @@ -74,46 +74,6 @@ impl<'a> Decoder<'a> {
self.bytes.is_none()
}

/// Get the position within the buffer.
pub fn position(&self) -> Length {
// TODO(tarcieri): avoid potential panic here
(self.position + self.offset).expect("overflow")
}

/// Peek at the next byte in the decoder without modifying the cursor.
pub fn peek_byte(&self) -> Option<u8> {
self.remaining()
.ok()
.and_then(|bytes| bytes.get(0).cloned())
}

/// Peek at the next byte in the decoder and attempt to decode it as a
/// [`Tag`] value.
///
/// Does not modify the decoder's state.
pub fn peek_tag(&self) -> Result<Tag> {
match self.peek_byte() {
Some(byte) => byte.try_into(),
None => {
let actual_len = self.input_len()?;
let expected_len = (actual_len + Length::ONE)?;
Err(ErrorKind::Incomplete {
expected_len,
actual_len,
}
.into())
}
}
}

/// Peek forward in the decoder, attempting to decode a [`Header`] from
/// the data at the current position in the decoder.
///
/// Does not modify the decoder's state.
pub fn peek_header(&self) -> Result<Header> {
Header::decode(&mut self.clone())
}

/// Finish decoding, returning the given value if there is no
/// remaining data, or an error otherwise
pub fn finish<T>(self, value: T) -> Result<T> {
Expand All @@ -130,14 +90,6 @@ impl<'a> Decoder<'a> {
}
}

/// Have we decoded all of the bytes in this [`Decoder`]?
///
/// Returns `false` if we're not finished decoding or if a fatal error
/// has occurred.
pub fn is_finished(&self) -> bool {
self.remaining().map(|rem| rem.is_empty()).unwrap_or(false)
}

/// Attempt to decode an ASN.1 `ANY` value.
pub fn any(&mut self) -> Result<Any<'a>> {
self.decode()
Expand Down Expand Up @@ -253,24 +205,58 @@ impl<'a> Decoder<'a> {
SequenceRef::decode(self)?.decode_body(f)
}

/// Decode a single byte, updating the internal cursor.
pub(crate) fn byte(&mut self) -> Result<u8> {
match self.bytes(1u8)? {
[byte] => Ok(*byte),
_ => {
/// Obtain a slice of bytes contain a complete TLV production suitable for parsing later.
pub fn tlv_bytes(&mut self) -> Result<&'a [u8]> {
let header = self.peek_header()?;
let header_len = header.encoded_len()?;
self.read_slice((header_len + header.length)?)
}

/// Obtain the remaining bytes in this decoder from the current cursor
/// position.
fn remaining(&self) -> Result<&'a [u8]> {
let pos = usize::try_from(self.position)?;

match self.bytes.and_then(|slice| slice.as_bytes().get(pos..)) {
Some(result) => Ok(result),
None => {
let actual_len = self.input_len()?;
let expected_len = (actual_len + Length::ONE)?;
Err(self.error(ErrorKind::Incomplete {
Err(ErrorKind::Incomplete {
expected_len,
actual_len,
}))
}
.at(self.position))
}
}
}
}

impl<'a> Reader<'a> for Decoder<'a> {
fn input_len(&self) -> Result<Length> {
Ok(self.bytes.ok_or(ErrorKind::Failed)?.len())
}

fn peek_byte(&self) -> Option<u8> {
self.remaining()
.ok()
.and_then(|bytes| bytes.get(0).cloned())
}

fn peek_header(&self) -> Result<Header> {
Header::decode(&mut self.clone())
}

fn position(&self) -> Length {
// TODO(tarcieri): avoid potential panic here
(self.position + self.offset).expect("overflow")
}

fn remaining_len(&self) -> Result<Length> {
self.remaining()?.len().try_into()
}

/// Obtain a slice of bytes of the given length from the current cursor
/// position, or return an error if we have insufficient data.
pub(crate) fn bytes(&mut self, len: impl TryInto<Length>) -> Result<&'a [u8]> {
fn read_slice(&mut self, len: impl TryInto<Length>) -> Result<&'a [u8]> {
if self.is_failed() {
return Err(self.error(ErrorKind::Failed));
}
Expand All @@ -295,38 +281,16 @@ impl<'a> Decoder<'a> {
}
}

/// Get the length of the input, if decoding hasn't failed.
pub(crate) fn input_len(&self) -> Result<Length> {
Ok(self.bytes.ok_or(ErrorKind::Failed)?.len())
}

/// Obtain a slice of bytes contain a complete TLV production suitable for parsing later.
pub fn tlv_bytes(&mut self) -> Result<&'a [u8]> {
let header = self.peek_header()?;
let header_len = header.encoded_len()?;
self.bytes((header_len + header.length)?)
}

/// Get the number of bytes still remaining in the buffer.
pub(crate) fn remaining_len(&self) -> Result<Length> {
self.remaining()?.len().try_into()
}

/// Obtain the remaining bytes in this decoder from the current cursor
/// position.
fn remaining(&self) -> Result<&'a [u8]> {
let pos = usize::try_from(self.position)?;

match self.bytes.and_then(|slice| slice.as_bytes().get(pos..)) {
Some(result) => Ok(result),
None => {
fn read_byte(&mut self) -> Result<u8> {
match self.read_slice(1u8)? {
[byte] => Ok(*byte),
_ => {
let actual_len = self.input_len()?;
let expected_len = (actual_len + Length::ONE)?;
Err(ErrorKind::Incomplete {
Err(self.error(ErrorKind::Incomplete {
expected_len,
actual_len,
}
.at(self.position))
}))
}
}
}
Expand All @@ -335,7 +299,7 @@ impl<'a> Decoder<'a> {
#[cfg(test)]
mod tests {
use super::Decoder;
use crate::{Decode, ErrorKind, Length, Tag};
use crate::{Decode, ErrorKind, Length, Reader, Tag};
use hex_literal::hex;

// INTEGER: 42
Expand Down
8 changes: 5 additions & 3 deletions der/src/document.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! ASN.1 DER-encoded documents stored on the heap.

use crate::{Decode, Decoder, Encode, Encoder, Error, FixedTag, Length, Result, Tag, Writer};
use crate::{
Decode, Decoder, Encode, Encoder, Error, FixedTag, Length, Reader, Result, Tag, Writer,
};
use alloc::vec::Vec;
use core::fmt::{self, Debug};

Expand Down Expand Up @@ -152,7 +154,7 @@ impl Decode<'_> for Document {
fn decode(decoder: &mut Decoder<'_>) -> Result<Document> {
let header = decoder.peek_header()?;
let length = (header.encoded_len()? + header.length)?;
let bytes = decoder.bytes(length)?;
let bytes = decoder.read_slice(length)?;
Ok(Self {
der_bytes: bytes.into(),
length,
Expand Down Expand Up @@ -335,7 +337,7 @@ fn decode_sequence<'a>(decoder: &mut Decoder<'a>) -> Result<&'a [u8]> {
header.tag.assert_eq(Tag::Sequence)?;

let len = (header.encoded_len()? + header.length)?;
decoder.bytes(len)
decoder.read_slice(len)
}

/// Write a file containing secret data to the filesystem, restricting the
Expand Down
10 changes: 7 additions & 3 deletions der/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ pub enum ErrorKind {
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
PermissionDenied,

/// Reader does not support the requested operation.
Reader,

/// Unknown tag mode.
TagModeUnknown,

Expand Down Expand Up @@ -298,7 +301,7 @@ impl fmt::Display for ErrorKind {
ErrorKind::DateTime => write!(f, "date/time error"),
ErrorKind::Failed => write!(f, "operation failed"),
#[cfg(feature = "std")]
ErrorKind::FileNotFound => f.write_str("file not found"),
ErrorKind::FileNotFound => write!(f, "file not found"),
ErrorKind::Incomplete {
expected_len,
actual_len,
Expand All @@ -318,13 +321,14 @@ impl fmt::Display for ErrorKind {
ErrorKind::OidUnknown { oid } => {
write!(f, "unknown/unsupported OID: {}", oid)
}
ErrorKind::SetOrdering => write!(f, "ordering error"),
ErrorKind::SetOrdering => write!(f, "SET OF ordering error"),
ErrorKind::Overflow => write!(f, "integer overflow"),
ErrorKind::Overlength => write!(f, "ASN.1 DER message is too long"),
#[cfg(feature = "pem")]
ErrorKind::Pem(e) => write!(f, "PEM error: {}", e),
#[cfg(feature = "std")]
ErrorKind::PermissionDenied => f.write_str("permission denied"),
ErrorKind::PermissionDenied => write!(f, "permission denied"),
ErrorKind::Reader => write!(f, "reader does not support the requested operation"),
ErrorKind::TagModeUnknown => write!(f, "unknown tag mode"),
ErrorKind::TagNumberInvalid => write!(f, "invalid tag number"),
ErrorKind::TagUnexpected { expected, actual } => {
Expand Down
6 changes: 3 additions & 3 deletions der/src/length.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Length calculations for encoded ASN.1 DER values

use crate::{Decode, Decoder, DerOrd, Encode, Encoder, Error, ErrorKind, Result, Writer};
use crate::{Decode, Decoder, DerOrd, Encode, Encoder, Error, ErrorKind, Reader, Result, Writer};
use core::{
cmp::Ordering,
fmt,
Expand Down Expand Up @@ -193,7 +193,7 @@ impl TryFrom<Length> for usize {

impl Decode<'_> for Length {
fn decode(decoder: &mut Decoder<'_>) -> Result<Length> {
match decoder.byte()? {
match decoder.read_byte()? {
// Note: per X.690 Section 8.1.3.6.1 the byte 0x80 encodes indefinite
// lengths, which are not allowed in DER, so disallow that byte.
len if len < 0x80 => Ok(len.into()),
Expand All @@ -205,7 +205,7 @@ impl Decode<'_> for Length {
let mut decoded_len = 0u32;
for _ in 0..nbytes {
decoded_len = decoded_len.checked_shl(8).ok_or(ErrorKind::Overflow)?
| u32::from(decoder.byte()?);
| u32::from(decoder.read_byte()?);
}

let length = Length::try_from(decoded_len)?;
Expand Down
Loading