Skip to content

Commit

Permalink
fix: decoding of extended fields in sequence in BER (#351)
Browse files Browse the repository at this point in the history
* BER: fix decoding of extended fields in seq/set

* Improve encoding and decoding of explicit prefix and extension additions

* Cleanup
  • Loading branch information
Nicceboy authored Oct 23, 2024
1 parent d1208da commit 021211b
Show file tree
Hide file tree
Showing 12 changed files with 289 additions and 51 deletions.
16 changes: 8 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 61 additions & 12 deletions macros/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -916,17 +916,18 @@ impl<'a> FieldConfig<'a> {
self.constraints.has_constraints(),
) {
(Some(true), _, _) => {
let or_else = if self.is_option_type() {
quote!(.ok())
if self.is_option_type() {
quote!(
decoder.decode_optional_with_explicit_prefix(#tag)?
)
} else if self.is_default_type() {
quote!(.ok().unwrap_or_else(#default_fn))
quote!(
decoder.decode_optional_with_explicit_prefix(#tag)?.unwrap_or_else(#default_fn)
)
} else {
// False positive
#[allow(clippy::redundant_clone)]
or_else.clone()
};

quote!(decoder.decode_explicit_prefix(#tag) #or_else)
quote!(decoder.decode_explicit_prefix(#tag) #or_else)
}
}
(Some(false), Some(path), true) => {
quote!(
Expand Down Expand Up @@ -979,35 +980,83 @@ impl<'a> FieldConfig<'a> {

if self.extension_addition {
match (
(self.tag.is_some() || self.container_config.automatic_tags)
.then(|| self.tag.as_ref().map_or(false, |tag| tag.is_explicit())),
self.default.as_ref().map(|path| {
path.as_ref()
.map_or(quote!(<_>::default), |path| quote!(#path))
}),
self.constraints.has_constraints(),
) {
(Some(path), true) => {
(Some(true), _, constraints) => {
let or_else = if self.is_option_type() {
quote!(.ok())
} else if self.is_default_type() {
quote!(.ok().unwrap_or_else(#default_fn))
} else {
// False positive
#[allow(clippy::redundant_clone)]
or_else.clone()
};
if constraints {
quote!(
decoder.decode_extension_addition_with_explicit_tag_and_constraints(
#tag,
<#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints),
) #or_else #handle_extension)
} else {
quote!(decoder.decode_extension_addition_with_explicit_tag_and_constraints(
#tag,
<#ty as #crate_root::AsnType>::CONSTRAINTS) #or_else #handle_extension)
}
}
(Some(false), Some(path), true) => {
quote!(
decoder.decode_extension_addition_with_default_and_tag_and_constraints(
#tag,
#path,
<#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints),
) #or_else
)
}
(Some(false), None, true) => {
quote!(
<_>::decode_extension_addition_with_tag_and_constraints(
decoder,
#tag,
<#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints),
) #or_else #handle_extension
)
}
(Some(false), Some(path), false) => {
quote!(decoder.decode_extension_addition_with_default_and_tag(#tag, #path) #or_else)
}
(Some(false), None, false) => {
quote!(<_>::decode_extension_addition_with_tag(decoder, #tag) #or_else #handle_extension)
}
(None, Some(path), true) => {
quote!(
decoder.decode_extension_addition_with_default_and_constraints(
#path,
<#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints),
) #or_else
)
}
(Some(path), false) => {
(None, Some(path), false) => {
quote!(
decoder.decode_extension_addition_with_default(
#path,
) #or_else
)
}
(None, true) => {
(None, None, true) => {
quote!(
decoder.decode_extension_addition_with_constraints(
<#ty as #crate_root::AsnType>::CONSTRAINTS.override_constraints(#constraints),
) #or_else
)
}
(None, false) => {
(None, None, false) => {
quote! {
decoder.decode_extension_addition() #or_else #handle_extension
}
Expand Down
4 changes: 4 additions & 0 deletions src/aper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,10 @@ mod tests {
};

let encoded = rasn::aper::encode(&connect_data).expect("failed to encode");
assert_eq!(
encoded,
vec![0x00, 0x05, 0x00, 0x14, 0x7C, 0x00, 0x01, 0x04, 0x00, 0x01, 0x02, 0x03]
);
let _: ConnectData = rasn::aper::decode(&encoded).expect("failed to decode");
}
}
34 changes: 34 additions & 0 deletions src/ber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,4 +383,38 @@ mod tests {
&[0x1f, 0x1f, 0x08, 0x32, 0x30, 0x31, 0x32, 0x31, 0x32, 0x32, 0x31]
);
}
#[test]
fn test_extended_sequence() {
use crate as rasn;
use rasn::prelude::*;
#[derive(AsnType, Debug, Clone, Encode, Decode, PartialEq)]
#[rasn(automatic_tags)]
#[non_exhaustive]
pub struct ExtendedInteger {
#[rasn(extension_addition)]
pub extension: Option<u64>,
}
round_trip!(
ber,
ExtendedInteger,
ExtendedInteger {
extension: Some(42)
},
&[0x30, 0x03, 0x80, 0x01, 0x2A]
);
#[derive(AsnType, Debug, Clone, Encode, Decode, PartialEq)]
#[non_exhaustive]
pub struct ExtendedExplicitInteger {
#[rasn(extension_addition)]
#[rasn(tag(explicit(5)))]
pub extension: u64,
}

round_trip!(
ber,
ExtendedExplicitInteger,
ExtendedExplicitInteger { extension: 42 },
&[0x30, 0x05, 0xA5, 0x03, 0x02, 0x01, 0x2A]
);
}
}
26 changes: 23 additions & 3 deletions src/ber/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ impl crate::Decoder for Decoder<'_> {
// If there are no fields, or the input is empty and we know that
// all fields are optional or default fields, we call the default
// initializer and skip calling the decode function at all.
if D::FIELDS.is_empty()
if D::FIELDS.is_empty() && D::EXTENDED_FIELDS.is_none()
|| (D::FIELDS.len() == D::FIELDS.number_of_optional_and_default_fields()
&& decoder.input.is_empty())
{
Expand All @@ -671,6 +671,14 @@ impl crate::Decoder for Decoder<'_> {
fn decode_explicit_prefix<D: Decode>(&mut self, tag: Tag) -> Result<D> {
self.parse_constructed_contents(tag, false, D::decode)
}
fn decode_optional_with_explicit_prefix<D: Decode>(
&mut self,
tag: Tag,
) -> Result<Option<D>, Self::Error> {
self.decode_explicit_prefix(tag)
.map(Some)
.or_else(|_| Ok(None))
}

fn decode_set<FIELDS, SET, D, F>(
&mut self,
Expand Down Expand Up @@ -736,15 +744,27 @@ impl crate::Decoder for Decoder<'_> {
D::from_tag(self, identifier.tag)
}

fn decode_extension_addition_with_constraints<D>(
fn decode_extension_addition_with_explicit_tag_and_constraints<D>(
&mut self,
tag: Tag,
_constraints: Constraints,
) -> core::result::Result<Option<D>, Self::Error>
where
D: Decode,
{
self.decode_explicit_prefix(tag).map(Some)
}

fn decode_extension_addition_with_tag_and_constraints<D>(
&mut self,
tag: Tag,
// Constraints are irrelevant using BER
_: Constraints,
) -> core::result::Result<Option<D>, Self::Error>
where
D: Decode,
{
<Option<D>>::decode(self)
<Option<D>>::decode_with_tag(self, tag)
}

fn decode_extension_addition_group<D: Decode + crate::types::Constructed>(
Expand Down
20 changes: 20 additions & 0 deletions src/coer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,26 @@ mod tests {
},
&[0b10000000, 0x01, 0x01, 0x03, 0x01, 0x02, 0x03]
);

#[derive(AsnType, Decode, Encode, Clone, Debug, PartialEq, Eq)]
pub struct SequenceOptionalsExplicit {
#[rasn(tag(explicit(0)))]
pub it: Integer,
#[rasn(tag(explicit(1)))]
pub is: Option<OctetString>,
#[rasn(tag(explicit(2)))]
pub late: Option<Integer>,
}
round_trip!(
coer,
SequenceOptionalsExplicit,
SequenceOptionalsExplicit {
it: 42.into(),
is: None,
late: None
},
&[0, 1, 42]
);
#[derive(AsnType, Decode, Encode, Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct SequenceDuplicatesExtended {
Expand Down
71 changes: 64 additions & 7 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ pub trait Decoder: Sized {

/// Decode an ASN.1 value that has been explicitly prefixed with `tag` from the available input.
fn decode_explicit_prefix<D: Decode>(&mut self, tag: Tag) -> Result<D, Self::Error>;
/// Decode an optional ASN.1 type that has been explicitly prefixed with `tag` from the available input.
fn decode_optional_with_explicit_prefix<D: Decode>(
&mut self,
tag: Tag,
) -> Result<Option<D>, Self::Error>;
/// Decode a `UtcTime` identified by `tag` from the available input.
fn decode_utc_time(&mut self, tag: Tag) -> Result<types::UtcTime, Self::Error>;
/// Decode a `GeneralizedTime` identified by `tag` from the available input.
Expand Down Expand Up @@ -276,13 +281,47 @@ pub trait Decoder: Sized {
.unwrap_or_else(default_fn))
}

/// Decode a extension addition value in a `SEQUENCE` or `SET`.
/// Decode an extension addition value in a `SEQUENCE` or `SET`.
fn decode_extension_addition<D>(&mut self) -> Result<Option<D>, Self::Error>
where
D: Decode,
{
self.decode_extension_addition_with_constraints(Constraints::default())
}
/// Decode an extension addition with explicit tag in a `SEQUENCE` or `SET`.
fn decode_extension_addition_with_explicit_tag_and_constraints<D>(
&mut self,
tag: Tag,
constraints: Constraints,
) -> Result<Option<D>, Self::Error>
where
D: Decode;

/// Decode an extension addition value with tag in a `SEQUENCE` or `SET`.
fn decode_extension_addition_with_tag<D>(&mut self, tag: Tag) -> Result<Option<D>, Self::Error>
where
D: Decode,
{
self.decode_extension_addition_with_tag_and_constraints(tag, Constraints::default())
}
/// Decode an extension addition with constraints in a `SEQUENCE` or `SET`
fn decode_extension_addition_with_constraints<D>(
&mut self,
constraints: Constraints,
) -> Result<Option<D>, Self::Error>
where
D: Decode,
{
self.decode_extension_addition_with_tag_and_constraints(D::TAG, constraints)
}
/// Decode a extension addition value with tag and constraints in a `SEQUENCE` or `SET`.
fn decode_extension_addition_with_tag_and_constraints<D>(
&mut self,
tag: Tag,
constraints: Constraints,
) -> Result<Option<D>, Self::Error>
where
D: Decode;

/// Decode a `DEFAULT` value in a `SEQUENCE`'s or `SET`'s extension
fn decode_extension_addition_with_default<D: Decode, F: FnOnce() -> D>(
Expand All @@ -294,6 +333,18 @@ pub trait Decoder: Sized {
Constraints::default(),
)
}
/// Decode a `DEFAULT` value with tag in a `SEQUENCE`'s or `SET`'s extension
fn decode_extension_addition_with_default_and_tag<D: Decode, F: FnOnce() -> D>(
&mut self,
tag: Tag,
default_fn: F,
) -> Result<D, Self::Error> {
self.decode_extension_addition_with_default_and_tag_and_constraints::<D, F>(
tag,
default_fn,
Constraints::default(),
)
}

/// Decode a `DEFAULT` value with constraints in a `SEQUENCE`'s or `SET`'s extension
fn decode_extension_addition_with_default_and_constraints<D: Decode, F: FnOnce() -> D>(
Expand All @@ -305,14 +356,20 @@ pub trait Decoder: Sized {
.decode_extension_addition_with_constraints::<D>(constraints)?
.unwrap_or_else(default_fn))
}

/// Decode an extension addition with constraints in a `SEQUENCE` or `SET`
fn decode_extension_addition_with_constraints<D>(
/// Decode a `DEFAULT` value with tag and constraints in a `SEQUENCE`'s or `SET`'s extension
fn decode_extension_addition_with_default_and_tag_and_constraints<
D: Decode,
F: FnOnce() -> D,
>(
&mut self,
tag: Tag,
default_fn: F,
constraints: Constraints,
) -> Result<Option<D>, Self::Error>
where
D: Decode;
) -> Result<D, Self::Error> {
Ok(self
.decode_extension_addition_with_tag_and_constraints::<D>(tag, constraints)?
.unwrap_or_else(default_fn))
}

/// Decode a extension addition group in a `SEQUENCE` or `SET`.
fn decode_extension_addition_group<D: Decode + crate::types::Constructed>(
Expand Down
Loading

0 comments on commit 021211b

Please sign in to comment.