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
170 changes: 170 additions & 0 deletions src/ber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,4 +460,174 @@ mod tests {
&[0x30, 0x05, 0xA5, 0x03, 0x02, 0x01, 0x2A]
);
}
#[test]
fn test_optional_any() {
// https://github.com/librasn/rasn/issues/488
use crate as rasn;
use rasn::prelude::*;

#[derive(Debug, AsnType, Decode, Encode, PartialEq, Eq)]
struct IncomingRequest {
#[rasn(tag(Context, 0))]
handshake: Option<Any>,
#[rasn(tag(Context, 1))]
user_data: Option<Any>,
}
let incoming: IncomingRequest = rasn::Codec::Ber
.decode_from_binary(&[0x30, 0x06, 0xA1, 0x04, 0x01, 0x02, 0x03, 0x04])
.unwrap();
let expected = IncomingRequest {
handshake: None,
user_data: Some(Any::new(vec![0x01, 0x02, 0x03, 0x04])),
};
assert_eq!(incoming, expected)
}

#[test]
fn test_optional_variants() {
use crate as rasn;
use rasn::prelude::*;

#[derive(AsnType, Debug, Clone, Encode, Decode, PartialEq)]
#[rasn(automatic_tags)]
#[rasn(choice)]
pub enum TestChoice {
Integer(i32),
Boolean(bool),
}

#[derive(AsnType, Debug, Clone, Encode, Decode, PartialEq)]
#[rasn(automatic_tags)]
pub struct TestSequence {
a: Option<u32>,
b: Option<TestChoice>,
c: Option<Any>,
d: bool, // A required field to ensure sequence isn't empty
}

// Case 1: All optional fields are absent.
let value1 = TestSequence {
a: None,
b: None,
c: None,
d: true,
};
// Sequence tag (0x30), length 3
// Boolean 'd' is implicitly tagged with [3]: tag (0x83), length 1, value TRUE (0xFF)
let expected1 = &[0x30, 0x03, 0x83, 0x01, 0xFF];
assert_eq!(encode(&value1).unwrap(), expected1);
assert_eq!(decode::<TestSequence>(expected1).unwrap(), value1);

// Case 2: 'a' is present, others absent.
let value2 = TestSequence {
a: Some(10),
b: None,
c: None,
d: true,
};
// Sequence tag (0x30), length 6
// Integer 'a' is implicitly tagged with [0]: tag (0x80), length 1, value 10
// Boolean 'd' is implicitly tagged with [3]: tag (0x83), length 1, value TRUE
let expected2 = &[0x30, 0x06, 0x80, 0x01, 0x0A, 0x83, 0x01, 0xFF];
assert_eq!(encode(&value2).unwrap(), expected2);
assert_eq!(decode::<TestSequence>(expected2).unwrap(), value2);

// Case 3: 'b' is present (as Integer), others absent.
let value3 = TestSequence {
a: None,
b: Some(TestChoice::Integer(20)),
c: None,
d: true,
};
// Sequence tag (0x30), length 8
// Choice 'b' is explicitly tagged with [1]: tag (0xA1), constructed, length 3
// Integer variant is implicitly tagged with [0]: tag (0x80), length 1, value 20
// Boolean 'd' is implicitly tagged with [3]: tag (0x83), length 1, value TRUE
let expected3 = &[0x30, 0x08, 0xA1, 0x03, 0x80, 0x01, 0x14, 0x83, 0x01, 0xFF];
assert_eq!(encode(&value3).unwrap(), expected3);
assert_eq!(decode::<TestSequence>(expected3).unwrap(), value3);

// Case 4: 'c' is present, others absent.
let any_payload = &[0x05, 0x00]; // NULL type
let value4 = TestSequence {
a: None,
b: None,
c: Some(Any::new(any_payload.to_vec())),
d: true,
};
// Sequence tag (0x30), length 7
// Any 'c' is implicitly tagged with [2]: tag (0x82), length 2, value [0x05, 0x00]
// Boolean 'd' is implicitly tagged with [3]: tag (0x83), length 1, value TRUE
let expected4 = &[0x30, 0x07, 0x82, 0x02, 0x05, 0x00, 0x83, 0x01, 0xFF];
assert_eq!(encode(&value4).unwrap(), expected4);
assert_eq!(decode::<TestSequence>(expected4).unwrap(), value4);

// Case 5: All optional fields present.
let value5 = TestSequence {
a: Some(255),
b: Some(TestChoice::Boolean(false)),
c: Some(Any::new(any_payload.to_vec())),
d: false,
};
// Sequence tag (0x30), length 16
// 'a' (u32, 255): implicitly tagged with [0] -> 80 02 00 FF
// 'b' (TestChoice::Boolean(false)): explicitly tagged with [1] -> A1 03 (content)
// 'Boolean' variant implicitly tagged with [1] -> 81 01 00
// 'c' (Any): implicitly tagged with [2] -> 82 02 05 00
// 'd' (bool, false): implicitly tagged with [3] -> 83 01 00
let expected5 = &[
0x30, 0x10, 0x80, 0x02, 0x00, 0xFF, 0xA1, 0x03, 0x81, 0x01, 0x00, 0x82, 0x02, 0x05,
0x00, 0x83, 0x01, 0x00,
];
assert_eq!(encode(&value5).unwrap(), expected5);
assert_eq!(decode::<TestSequence>(expected5).unwrap(), value5);

// Case 6: 'a' and 'c' are present.
let value6 = TestSequence {
a: Some(1),
b: None,
c: Some(Any::new(any_payload.to_vec())),
d: true,
};
// Sequence tag (0x30), length 10
// 'a' (u32, 1): implicitly tagged with [0] -> 80 01 01
// 'c' (Any): implicitly tagged with [2] -> 82 02 05 00
// 'd' (bool, true): implicitly tagged with [3] -> 83 01 FF
let expected6 = &[
0x30, 0x0A, 0x80, 0x01, 0x01, 0x82, 0x02, 0x05, 0x00, 0x83, 0x01, 0xFF,
];
assert_eq!(encode(&value6).unwrap(), expected6);
assert_eq!(decode::<TestSequence>(expected6).unwrap(), value6);

// Another type where the final field is optional
#[derive(AsnType, Debug, Clone, Encode, Decode, PartialEq)]
#[rasn(automatic_tags)]
pub struct AnotherTestSequence {
a: Option<TestChoice>,
b: Option<Any>,
}
let value1 = AnotherTestSequence { a: None, b: None };
// Sequence tag (0x30), length 0
let expected1 = &[0x30, 0x00];
assert_eq!(encode(&value1).unwrap(), expected1);
assert_eq!(decode::<AnotherTestSequence>(expected1).unwrap(), value1);
let value2 = AnotherTestSequence {
a: Some(TestChoice::Boolean(true)),
b: None,
};
// Sequence tag (0x30), length 5
// 'a' (TestChoice): explicitly tagged with [0] -> A0 03
// 'Boolean' (bool, true): implicitly tagged with [1] -> 81 01 FF
let expected2 = &[0x30, 0x05, 0xA0, 0x03, 0x81, 0x01, 0xFF];
assert_eq!(encode(&value2).unwrap(), expected2);
assert_eq!(decode::<AnotherTestSequence>(expected2).unwrap(), value2);
let value3 = AnotherTestSequence {
a: None,
b: Some(Any::new(any_payload.to_vec())),
};
// Sequence tag (0x30), length 4
// 'b' (Any, NULL): implicitly tagged with [1] -> 81 02 05 00
let expected3 = &[0x30, 0x04, 0x81, 0x02, 0x05, 0x00];
assert_eq!(encode(&value3).unwrap(), expected3);
}
}
87 changes: 67 additions & 20 deletions src/ber/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,42 @@ impl<'input> Decoder<'input> {
pub fn decoded_len(&self) -> usize {
self.initial_len - self.input.len()
}
/// Peek the value of the next tag
pub fn peek_tag(&self) -> Result<Tag> {
let (_, tag_ident) =
self::parser::parse_identifier_octet(self.input).map_err(|e| match e {
ParseNumberError::Nom(e) => {
DecodeError::map_nom_err(e, self.config.current_codec())
}
ParseNumberError::Overflow => {
DecodeError::integer_overflow(32u32, self.config.current_codec())
}
})?;
Ok(tag_ident.tag)
}
/// Generic helper used by the optional decoders.
/// The function will peek the upcoming tag and only invoke `f` when the tags match.
/// If tags won't match or input is empty, will return `None`
fn decode_optional_with_check<D, F>(&mut self, tag: Tag, f: F) -> Result<Option<D>, DecodeError>
where
F: FnOnce(&mut Self) -> Result<D, DecodeError>,
{
if self.input.is_empty() {
return Ok(None);
}
// Special case if optional is absent and idefinite length EOC follows
if self.input.len() >= 2 && &self.input[..2] == EOC && !self.config.encoding_rules.is_der()
{
return Ok(None);
}
if tag != Tag::EOC {
let upcoming_tag = self.peek_tag()?;
if tag != upcoming_tag {
return Ok(None);
}
}
Ok(Some(f(self)?))
}

fn parse_eoc(&mut self) -> Result<()> {
let (i, _) = nom::bytes::streaming::tag(EOC)(self.input)
Expand Down Expand Up @@ -320,26 +356,37 @@ impl<'input> crate::Decoder for Decoder<'input> {
fn codec(&self) -> crate::Codec {
Self::codec(self)
}
fn decode_any(&mut self) -> Result<types::Any> {
fn decode_any(&mut self, tag: Tag) -> Result<types::Any> {
// If tag is not EOC, we are likely in sequence/set
let tag = if tag == Tag::EOC { None } else { Some(tag) };
// `parse_value` consumes the Tag and Length.
// `input` is the remaining slice, starting at the beginning of the Value.
// `contents` is `Some(value)` for definite-length, and `None` for indefinite-length.
let (mut input, (identifier, contents)) =
self::parser::parse_value(self.config, self.input, None)?;
self::parser::parse_value(self.config, self.input, tag)?;

if contents.is_none() {
let (i, _) = self::parser::parse_encoded_value(
let contents = if let Some(definitive_contents) = contents {
definitive_contents.to_vec()
} else {
let (i, indefinitive_contents) = self::parser::parse_encoded_value(
self.config,
self.input,
identifier.tag,
|input, _| Ok(alloc::vec::Vec::from(input)),
)?;
input = i;
}
let diff = self.input.len() - input.len();
let contents = &self.input[..diff];
indefinitive_contents
};
// Only the data format is validated, when not in Sequence/Set - afterwards just pass the original data.
let any = if tag.is_none() {
let diff = self.input.len() - input.len();
types::Any::new(self.input[..diff].to_vec())
} else {
// Outermost TLV stripped in sequence/set
types::Any::new(contents)
};
self.input = input;

Ok(types::Any {
contents: contents.to_vec(),
})
Ok(any)
}

fn decode_bool(&mut self, tag: Tag) -> Result<bool> {
Expand Down Expand Up @@ -734,33 +781,33 @@ impl<'input> crate::Decoder for Decoder<'input> {
}

fn decode_optional<D: Decode>(&mut self) -> Result<Option<D>, Self::Error> {
if D::TAG == Tag::EOC {
Ok(D::decode(self).ok())
} else {
self.decode_optional_with_tag(D::TAG)
}
self.decode_optional_with_check(D::TAG, |decoder| D::decode(decoder))
}

/// Decode an the optional value in a `SEQUENCE` or `SET` with `tag`.
/// Decode the optional value in a `SEQUENCE` or `SET` with `tag`.
/// Passing the correct tag is required even when used with codecs where
/// the tag is not present.
fn decode_optional_with_tag<D: Decode>(&mut self, tag: Tag) -> Result<Option<D>, Self::Error> {
Ok(D::decode_with_tag(self, tag).ok())
self.decode_optional_with_check(tag, |decoder| D::decode_with_tag(decoder, tag))
}

fn decode_optional_with_constraints<D: Decode>(
&mut self,
constraints: Constraints,
) -> Result<Option<D>, Self::Error> {
Ok(D::decode_with_constraints(self, constraints).ok())
self.decode_optional_with_check(D::TAG, |decoder| {
D::decode_with_constraints(decoder, constraints)
})
}

fn decode_optional_with_tag_and_constraints<D: Decode>(
&mut self,
tag: Tag,
constraints: Constraints,
) -> Result<Option<D>, Self::Error> {
Ok(D::decode_with_tag_and_constraints(self, tag, constraints).ok())
self.decode_optional_with_check(tag, |decoder| {
D::decode_with_tag_and_constraints(decoder, tag, constraints)
})
}

fn decode_choice<D>(&mut self, _: Constraints) -> Result<D, Self::Error>
Expand Down
20 changes: 17 additions & 3 deletions src/ber/enc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,15 +329,29 @@ impl crate::Encoder<'_> for Encoder {

fn encode_any(
&mut self,
_: Tag,
tag: Tag,
value: &types::Any,
_: crate::types::Identifier,
_identifier: crate::types::Identifier,
) -> Result<Self::Ok, Self::Error> {
if self.is_set_encoding {
return Err(BerEncodeErrorKind::AnyInSet.into());
}

self.output.extend_from_slice(&value.contents);
let inner = value.as_bytes();
if inner.is_empty() {
return Ok(());
}
// If we have Any type or Choice type directly, don't encode the tag
if tag != Tag::EOC {
let inner_constructed = (inner[0] & 0x20) != 0;
let ident = Identifier::from_tag(tag, inner_constructed);
let ident_bytes = self.encode_identifier(ident);
self.append_byte_or_bytes(ident_bytes);
self.encode_length(ident, inner);
self.encode_to_set(ident.tag);
} else {
self.output.extend_from_slice(inner);
}

Ok(())
}
Expand Down
6 changes: 3 additions & 3 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ pub trait Decoder<const RCL: usize = 0, const ECL: usize = 0>: Sized {
fn codec(&self) -> crate::Codec;

/// Decode an unknown ASN.1 value identified by `tag` from the available input.
fn decode_any(&mut self) -> Result<types::Any, Self::Error>;
fn decode_any(&mut self, tag: Tag) -> Result<types::Any, Self::Error>;
/// Decode a `BIT STRING` identified by `tag` from the available input.
fn decode_bit_string(
&mut self,
Expand Down Expand Up @@ -755,10 +755,10 @@ impl Decode for types::GeneralizedTime {
impl Decode for types::Any {
fn decode_with_tag_and_constraints<D: Decoder>(
decoder: &mut D,
_: Tag,
tag: Tag,
_: Constraints,
) -> Result<Self, D::Error> {
decoder.decode_any()
decoder.decode_any(tag)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/jer/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl crate::Decoder for Decoder {
type Error = DecodeError;
type AnyDecoder<const R: usize, const E: usize> = Self;

fn decode_any(&mut self) -> Result<Any, Self::Error> {
fn decode_any(&mut self, _tag: Tag) -> Result<Any, Self::Error> {
decode_jer_value!(Self::any_from_value, self.stack)
}

Expand Down
2 changes: 1 addition & 1 deletion src/jer/enc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl crate::Encoder<'_> for Encoder {
self.encode_octet_string(
t,
Constraints::default(),
&value.contents,
value.as_bytes(),
Identifier::EMPTY,
)
}
Expand Down
7 changes: 5 additions & 2 deletions src/oer/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,8 +481,11 @@ impl<'input, const RFC: usize, const EFC: usize> crate::Decoder for Decoder<'inp
self.codec()
}

fn decode_any(&mut self) -> Result<Any, Self::Error> {
panic!("Not every type can be decoded as Any in OER.")
/// In OER, an alias for decoding an open type and obtaining the underlying type's encoded bytes.
fn decode_any(&mut self, tag: Tag) -> Result<Any, Self::Error> {
Ok(Any::new(
self.decode_octet_string(tag, Constraints::default())?,
))
}

fn decode_bit_string(
Expand Down
Loading
Loading