Skip to content

Commit

Permalink
feat: add decode_implicit and decode_explicit back
Browse files Browse the repository at this point in the history
  • Loading branch information
dishmaker committed Oct 6, 2024
1 parent 7ce6ee5 commit dc2e67f
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 59 deletions.
7 changes: 4 additions & 3 deletions der/src/asn1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod bmp_string;
mod boolean;
mod choice;
mod context_specific;
mod custom_class;
mod generalized_time;
mod ia5_string;
mod integer;
Expand All @@ -30,22 +31,22 @@ mod teletex_string;
mod utc_time;
mod utf8_string;
mod videotex_string;
mod custom_class;

pub use self::{
any::AnyRef,
bit_string::{BitStringIter, BitStringRef},
choice::Choice,
//context_specific::{ContextSpecific, ContextSpecificRef},
context_specific::{ContextSpecific},
context_specific::ContextSpecific,
custom_class::{AnyCustomClassExplicit, AnyCustomClassImplicit},
generalized_time::GeneralizedTime,
ia5_string::Ia5StringRef,
integer::{int::IntRef, uint::UintRef},
null::Null,
octet_string::OctetStringRef,
printable_string::PrintableStringRef,
//private::{Private, PrivateRef},
private::{Private},
private::Private,
sequence::{Sequence, SequenceRef},
sequence_of::{SequenceOf, SequenceOfIter},
set_of::{SetOf, SetOfIter},
Expand Down
22 changes: 20 additions & 2 deletions der/src/asn1/context_specific.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use crate::{
};
use core::cmp::Ordering;

use super::custom_class::{self, CustomClass, CustomClassImplicit};
use super::custom_class::{
self, AnyCustomClassExplicit, AnyCustomClassImplicit, CustomClass, CustomClassImplicit,
};

/// Context-specific class, EXPLICIT
pub type ContextSpecific<const TAG: u16, T> = CustomClass<T, TAG, CLASS_CONTEXT_SPECIFIC>;
Expand All @@ -20,8 +22,24 @@ pub fn decode_implicit<'a, R: Reader<'a>, T: Tagged + DecodeValue<'a>>(
number: TagNumber,
reader: &mut R,
) -> Result<Option<T>, T::Error> {
custom_class::decode_implicit(Class::ContextSpecific, number, reader)
match AnyCustomClassImplicit::decode_implicit(Class::ContextSpecific, number, reader) {
Ok(Some(custom)) => Ok(Some(custom.value)),
Ok(None) => Ok(None),
Err(err) => Err(err),
}
}

pub fn decode_explicit<'a, R: Reader<'a>, T: Decode<'a>>(
number: TagNumber,
reader: &mut R,
) -> Result<Option<T>, T::Error> {
match AnyCustomClassExplicit::decode_explicit(Class::ContextSpecific, number, reader) {
Ok(Some(custom)) => Ok(Some(custom.value)),
Ok(None) => Ok(None),
Err(err) => Err(err),
}
}

// /// Context-specific field which wraps an owned inner value.
// ///
// /// This type decodes/encodes a field which is specific to a particular context
Expand Down
89 changes: 68 additions & 21 deletions der/src/asn1/custom_class.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use core::cmp::Ordering;
use core::num;

use super::{AnyRef, Choice};
use crate::encode::Encode;
use crate::{
Class, Decode, DecodeValue, DerOrd, EncodeValue, Error, FixedTag, Header, Length, Reader,
SliceReader, Tag, TagNumber, Tagged, ValueOrd, Writer,
SliceReader, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer,
};

/// Application, Context-specific or Private class field which wraps an owned inner value.
Expand Down Expand Up @@ -43,9 +44,13 @@ impl<T, const TAG: u16, const CLASS: u8> CustomClass<T, TAG, CLASS> {
where
T: Decode<'a>,
{
decode_with(reader, Class::from(CLASS), TagNumber(TAG), |reader| {
Self::decode(reader)
})
match AnyCustomClassExplicit::decode_explicit(Class::from(CLASS), TagNumber(TAG), reader) {
Ok(Some(custom)) => Ok(Some(Self {
value: custom.value,
})),
Ok(None) => Ok(None),
Err(err) => Err(err),
}
}
}

Expand All @@ -72,14 +77,14 @@ fn decode_with<'a, F, R: Reader<'a>, E, T>(
f: F,
) -> Result<Option<T>, E>
where
F: FnOnce(&mut R) -> Result<T, E>,
F: FnOnce(Tag, &mut R) -> Result<T, E>,
E: From<Error>,
{
while let Some(tag) = Tag::peek_optional(reader)? {
if is_unskippable_tag(tag, expected_class, expected_number) {
break;
} else if tag.number() == expected_number {
return Some(f(reader)).transpose();
return Some(f(tag, reader)).transpose();
} else {
AnyRef::decode(reader)?;
}
Expand All @@ -99,29 +104,71 @@ impl<T, const TAG: u16, const CLASS: u8> CustomClassImplicit<T, TAG, CLASS> {
where
T: DecodeValue<'a> + Tagged,
{
match decode_implicit(Class::from(CLASS), TagNumber(TAG), reader) {
Ok(Some(value)) => Ok(Some(Self { value })),
match AnyCustomClassImplicit::decode_implicit(Class::from(CLASS), TagNumber(TAG), reader) {
Ok(Some(custom)) => Ok(Some(Self {
value: custom.value,
})),
Ok(None) => Ok(None),
Err(err) => Err(err),
}
}
}

pub fn decode_implicit<'a, R: Reader<'a>, T: Tagged + DecodeValue<'a>>(
class: Class,
number: TagNumber,
reader: &mut R,
) -> Result<Option<T>, T::Error> {
decode_with::<_, _, T::Error, _>(reader, class, number, |reader| {
let header = Header::decode(reader)?;
let value = T::decode_value(reader, header)?;
pub struct AnyCustomClassExplicit<T> {
pub tag_number: TagNumber,
pub constructed: bool,
pub value: T,
}

if header.tag.is_constructed() != value.tag().is_constructed() {
return Err(header.tag.non_canonical_error().into());
}
pub struct AnyCustomClassImplicit<T> {
pub tag_number: TagNumber,
pub constructed: bool,
pub value: T,
}

Ok(value)
})
impl<'a, T> AnyCustomClassExplicit<T>
where
T: Decode<'a>,
{
pub fn decode_explicit<R: Reader<'a>>(
class: Class,
number: TagNumber,
reader: &mut R,
) -> Result<Option<Self>, T::Error> {
decode_with(reader, class, number, |tag, reader| {
Ok(Self {
value: T::decode(reader)?,
tag_number: tag.number(),
constructed: tag.is_constructed(),
})
})
}
}

impl<'a, T> AnyCustomClassImplicit<T>
where
T: Tagged + DecodeValue<'a>,
{
pub fn decode_implicit<R: Reader<'a>>(
class: Class,
number: TagNumber,
reader: &mut R,
) -> Result<Option<Self>, T::Error> {
decode_with::<_, _, T::Error, _>(reader, class, number, |_tag, reader| {
let header = Header::decode(reader)?;
let value = T::decode_value(reader, header)?;

if header.tag.is_constructed() != value.tag().is_constructed() {
return Err(header.tag.non_canonical_error().into());
}

Ok(Self {
tag_number: header.tag.number(),
constructed: header.tag.is_constructed(),
value,
})
})
}
}

impl<'a, T, const TAG: u16, const CLASS: u8> Choice<'a> for CustomClass<T, TAG, CLASS>
Expand Down
9 changes: 2 additions & 7 deletions der/src/asn1/private.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
//! Private field.
use crate::tag::{CLASS_APPLICATION, CLASS_CONTEXT_SPECIFIC, CLASS_PRIVATE};
use crate::{Class, FixedTag};
use crate::{
asn1::AnyRef, Choice, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, Error,
Header, Length, Reader, SliceReader, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer,
};
use crate::{Class, FixedTag};
use core::cmp::Ordering;

use super::custom_class::{CustomClass, CustomClassImplicit};

/// Application class, EXPLICIT
pub type Application<const TAG: u16, T> = CustomClass<T, TAG, CLASS_APPLICATION>;



/// Private class, EXPLICIT
pub type Private<const TAG: u16, T> = CustomClass<T, TAG, CLASS_PRIVATE>;

/// Application class, IMPLICIT
pub type ApplicationImplicit<const TAG: u16, T> = CustomClassImplicit<T, TAG, CLASS_APPLICATION>;


/// Private class, IMPLICIT
pub type PrivateImplicit<const TAG: u16, T> = CustomClassImplicit<T, TAG, CLASS_PRIVATE>;


// /// Private field reference.
// ///
// /// This type encodes a field which is whose meaning is specific to a given
Expand Down Expand Up @@ -145,8 +141,7 @@ mod tests {
#[test]
fn private_not_skipping_unknown_field() {
let mut reader = SliceReader::new(&hex!("E003020100E103020101")).unwrap();
let field = Private::<1, u8>::decode_optional(&mut reader)
.unwrap();
let field = Private::<1, u8>::decode_optional(&mut reader).unwrap();
assert_eq!(field, None);
}

Expand Down
22 changes: 16 additions & 6 deletions der/src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ pub(crate) mod pem;
pub(crate) mod slice;

use crate::{
asn1::ContextSpecific, Decode, DecodeValue, Encode, EncodingRules, Error, ErrorKind, FixedTag,
Header, Length, Tag, TagMode, TagNumber,
asn1::{AnyCustomClassExplicit, AnyCustomClassImplicit, ContextSpecific},
Class, Decode, DecodeValue, Encode, EncodingRules, Error, ErrorKind, FixedTag, Header, Length,
Tag, TagMode, TagNumber,
};

#[cfg(feature = "alloc")]
Expand Down Expand Up @@ -55,10 +56,19 @@ pub trait Reader<'r>: Sized {
T: DecodeValue<'r> + FixedTag + 'r,
{
Ok(match tag_mode {
TagMode::Explicit => ContextSpecific::<T>::decode_explicit(self, tag_number)?,
TagMode::Implicit => decode_implicit(tag_number, self)?,
}
.map(|field| field.value))
TagMode::Explicit => AnyCustomClassExplicit::<T>::decode_explicit(
Class::ContextSpecific,
tag_number,
self,
)?
.map(|field| field.value),
TagMode::Implicit => AnyCustomClassImplicit::<T>::decode_implicit(
Class::ContextSpecific,
tag_number,
self,
)?
.map(|field| field.value),
})
}

/// Decode a value which impls the [`Decode`] trait.
Expand Down
5 changes: 4 additions & 1 deletion der/src/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ mod mode;
mod number;

pub use self::{class::Class, mode::TagMode, number::TagNumber};
pub use self::{class::CLASS_UNIVERSAL, class::CLASS_CONTEXT_SPECIFIC, class::CLASS_APPLICATION, class::CLASS_PRIVATE};
pub use self::{
class::CLASS_APPLICATION, class::CLASS_CONTEXT_SPECIFIC, class::CLASS_PRIVATE,
class::CLASS_UNIVERSAL,
};

use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Writer};
use core::{cmp::Ordering, fmt};
Expand Down
4 changes: 2 additions & 2 deletions der/src/tag/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl From<u8> for Class {
0b01 => Class::Application,
0b10 => Class::ContextSpecific,
0b11 => Class::Private,
_ => unreachable!()
_ => unreachable!(),
}
}
}
Expand All @@ -62,4 +62,4 @@ impl Class {
pub const fn bits(&self) -> u8 {
*self as u8
}
}
}
35 changes: 18 additions & 17 deletions der/src/writer/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,23 +66,24 @@ impl<'a> SliceWriter<'a> {
.ok_or_else(|| ErrorKind::Overlength.at(position))
}

/// Encode a `CONTEXT-SPECIFIC` field with the provided tag number and mode.
pub fn context_specific<T>(
&mut self,
tag_number: TagNumber,
tag_mode: TagMode,
value: &T,
) -> Result<()>
where
T: EncodeValue + Tagged,
{
ContextSpecificRef {
tag_number,
tag_mode,
value,
}
.encode(self)
}
// TODO
// /// Encode a `CONTEXT-SPECIFIC` field with the provided tag number and mode.
// pub fn context_specific<T>(
// &mut self,
// tag_number: TagNumber,
// tag_mode: TagMode,
// value: &T,
// ) -> Result<()>
// where
// T: EncodeValue + Tagged,
// {
// ContextSpecificRef {
// tag_number,
// tag_mode,
// value,
// }
// .encode(self)
// }

/// Encode an ASN.1 `SEQUENCE` of the given length.
///
Expand Down

0 comments on commit dc2e67f

Please sign in to comment.