Skip to content
Draft
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
6 changes: 3 additions & 3 deletions macros/macros_impl/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,7 @@ impl<'a> FieldConfig<'a> {
)?;
)
} else if self.extension_addition_group {
quote!(encoder.encode_extension_addition_group(#this #field.as_ref(), #identifier)?;)
quote!(encoder.encode_extension_addition_group(#tag, #this #field.as_ref(), #identifier)?;)
} else {
match (self.constraints.has_constraints(), self.default.is_some()) {
(true, true) => {
Expand Down Expand Up @@ -959,7 +959,7 @@ impl<'a> FieldConfig<'a> {
)?;
)
} else if self.extension_addition_group {
quote!(encoder.encode_extension_addition_group(#this #field.as_ref(), #identifier)?;)
quote!(encoder.encode_extension_addition_group(#tag, #this #field.as_ref(), #identifier)?;)
} else {
match (self.constraints.has_constraints(), self.default.is_some()) {
(true, true) => {
Expand Down Expand Up @@ -1063,7 +1063,7 @@ impl<'a> FieldConfig<'a> {
};

let decode = if self.extension_addition_group {
quote!(decoder.decode_extension_addition_group() #or_else)
quote!(decoder.decode_extension_addition_group(#tag) #or_else)
} else {
match (
(self.tag.is_some() || self.container_config.automatic_tags)
Expand Down
2 changes: 1 addition & 1 deletion macros/macros_impl/src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ pub fn derive_struct_impl(
let decode_impl = if config.extension_addition {
quote!(#field_name(decoder.decode_extension_addition()?))
} else if config.extension_addition_group {
quote!(#field_name(decoder.decode_extension_addition_group()?))
quote!(#field_name(decoder.decode_extension_addition_group(#tag)?))
} else {
quote!(<_>::decode(decoder)?)
};
Expand Down
16 changes: 16 additions & 0 deletions src/ber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,22 @@ mod rules;
pub use identifier::Identifier;
pub(crate) use rules::EncodingRules;

#[derive(Clone, Copy, Debug)]
pub(crate) enum ExtensionGroupState {
None,
Pending(crate::types::Tag),
Active(crate::types::Tag),
}

impl ExtensionGroupState {
pub(crate) fn base_tag(self) -> Option<crate::types::Tag> {
match self {
Self::Pending(tag) | Self::Active(tag) => Some(tag),
Self::None => None,
}
}
}

/// Attempts to decode `T` from `input` using BER.
/// # Errors
/// Returns error specific to BER decoder if decoding is not possible.
Expand Down
71 changes: 68 additions & 3 deletions src/ber/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
mod config;
pub(super) mod parser;

use super::identifier::Identifier;
use super::{identifier::Identifier, ExtensionGroupState};
use crate::{
types::{
self,
Expand All @@ -29,6 +29,7 @@ pub struct Decoder<'input> {
input: &'input [u8],
config: DecoderOptions,
initial_len: usize,
extension_group: ExtensionGroupState,
}

impl<'input> Decoder<'input> {
Expand All @@ -49,9 +50,14 @@ impl<'input> Decoder<'input> {
input,
config,
initial_len: input.len(),
extension_group: ExtensionGroupState::None,
}
}

fn translate_tag(&self, tag: Tag) -> Tag {
tag.with_context_offset(self.extension_group.base_tag())
}

/// Return a number of the decoded bytes by this decoder
#[must_use]
pub fn decoded_len(&self) -> usize {
Expand Down Expand Up @@ -85,6 +91,9 @@ impl<'input> Decoder<'input> {
{
return Ok(None);
}

let tag = self.translate_tag(tag);

if tag != Tag::EOC {
let upcoming_tag = self.peek_tag()?;
if tag != upcoming_tag {
Expand All @@ -102,13 +111,15 @@ impl<'input> Decoder<'input> {
}

pub(crate) fn parse_value(&mut self, tag: Tag) -> Result<(Identifier, Option<&'input [u8]>)> {
let tag = self.translate_tag(tag);
let (input, (identifier, contents)) =
self::parser::parse_value(self.config, self.input, Some(tag))?;
self.input = input;
Ok((identifier, contents))
}

pub(crate) fn parse_primitive_value(&mut self, tag: Tag) -> Result<(Identifier, &'input [u8])> {
let tag = self.translate_tag(tag);
let (input, (identifier, contents)) =
self::parser::parse_value(self.config, self.input, Some(tag))?;
self.input = input;
Expand Down Expand Up @@ -762,6 +773,28 @@ impl<'input> crate::Decoder for Decoder<'input> {
default_initializer_fn: Option<DF>,
decode_fn: F,
) -> Result<D> {
if tag == Tag::SEQUENCE && matches!(self.extension_group, ExtensionGroupState::Pending(_)) {
// Extension addition groups are encoded flattened: skip the SEQUENCE wrapper once.
if let ExtensionGroupState::Pending(tag) = self.extension_group {
self.extension_group = ExtensionGroupState::Active(tag);
}
return if D::FIELDS.is_empty() && D::EXTENDED_FIELDS.is_none()
|| (D::FIELDS.len() == D::FIELDS.number_of_optional_and_default_fields()
&& self.input.is_empty())
{
if let Some(default_initializer_fn) = default_initializer_fn {
Ok((default_initializer_fn)())
} else {
Err(DecodeError::from_kind(
DecodeErrorKind::UnexpectedEmptyInput,
self.codec(),
))
}
} else {
(decode_fn)(self)
};
}

self.parse_constructed_contents(tag, true, |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
Expand Down Expand Up @@ -806,7 +839,7 @@ impl<'input> crate::Decoder for Decoder<'input> {
D: Fn(&mut Self, usize, Tag) -> Result<FIELDS, Self::Error>,
F: FnOnce(Vec<FIELDS>) -> Result<SET, Self::Error>,
{
self.parse_constructed_contents(tag, true, |decoder| {
let collect_fields = |decoder: &mut Self| -> Result<Vec<FIELDS>, Self::Error> {
let mut fields = Vec::new();

loop {
Expand All @@ -823,6 +856,20 @@ impl<'input> crate::Decoder for Decoder<'input> {
}
}

Ok(fields)
};

if tag == Tag::SET && matches!(self.extension_group, ExtensionGroupState::Pending(_)) {
// Extension addition groups are encoded flattened: skip the SET wrapper once.
if let ExtensionGroupState::Pending(tag) = self.extension_group {
self.extension_group = ExtensionGroupState::Active(tag);
}
let fields = collect_fields(self)?;
return (field_fn)(fields);
}

self.parse_constructed_contents(tag, true, |decoder| {
let fields = collect_fields(decoder)?;
(field_fn)(fields)
})
}
Expand Down Expand Up @@ -897,8 +944,26 @@ impl<'input> crate::Decoder for Decoder<'input> {
D: Decode + crate::types::Constructed<RL, EL>,
>(
&mut self,
tag: Tag,
) -> Result<Option<D>, Self::Error> {
<Option<D>>::decode(self)
if self.input.is_empty() {
return Ok(None);
}

let (_, identifier) = parser::parse_identifier_octet(self.input).map_err(|e| match e {
ParseNumberError::Nom(e) => DecodeError::map_nom_err(e, self.codec()),
ParseNumberError::Overflow => DecodeError::integer_overflow(32u32, self.codec()),
})?;

if identifier.tag == tag {
let previous = self.extension_group;
self.extension_group = ExtensionGroupState::Pending(tag);
let result = D::decode(self).map(Some);
self.extension_group = previous;
result
} else {
Ok(None)
}
}
}

Expand Down
42 changes: 40 additions & 2 deletions src/ber/enc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod config;
use alloc::{borrow::ToOwned, collections::VecDeque, string::ToString, vec::Vec};
use chrono::Timelike;

use super::Identifier;
use super::{ExtensionGroupState, Identifier};
use crate::{
bits::octet_string_ascending,
types::{
Expand All @@ -28,6 +28,7 @@ pub struct Encoder {
config: EncoderOptions,
is_set_encoding: bool,
set_buffer: alloc::collections::BTreeMap<Tag, Vec<u8>>,
extension_group: ExtensionGroupState,
}

/// A convenience type around results needing to return one or many bytes.
Expand All @@ -45,6 +46,7 @@ impl Encoder {
is_set_encoding: false,
output: <_>::default(),
set_buffer: <_>::default(),
extension_group: ExtensionGroupState::None,
}
}

Expand All @@ -63,6 +65,7 @@ impl Encoder {
is_set_encoding: true,
output: <_>::default(),
set_buffer: <_>::default(),
extension_group: ExtensionGroupState::None,
}
}

Expand All @@ -78,9 +81,14 @@ impl Encoder {
config,
is_set_encoding: false,
set_buffer: <_>::default(),
extension_group: ExtensionGroupState::None,
}
}

fn translate_tag(&self, tag: Tag) -> Tag {
tag.with_context_offset(self.extension_group.base_tag())
}

/// Consumes the encoder and returns the output of the encoding.
#[must_use]
pub fn output(self) -> Vec<u8> {
Expand Down Expand Up @@ -243,6 +251,10 @@ impl Encoder {

/// Encodes a given ASN.1 BER value with the `identifier`.
fn encode_value(&mut self, identifier: Identifier, value: &[u8]) {
let identifier = Identifier::from_tag(
self.translate_tag(identifier.tag),
identifier.is_constructed,
);
let ident_bytes = self.encode_identifier(identifier);
self.append_byte_or_bytes(ident_bytes);
self.encode_length(identifier, value);
Expand Down Expand Up @@ -711,6 +723,14 @@ impl crate::Encoder<'_> for Encoder {
C: crate::types::Constructed<RC, EC>,
F: FnOnce(&mut Self::AnyEncoder<'b, 0, 0>) -> Result<(), Self::Error>,
{
if tag == Tag::SEQUENCE && matches!(self.extension_group, ExtensionGroupState::Pending(_)) {
// Extension addition groups are encoded flattened: skip the SEQUENCE wrapper once.
if let ExtensionGroupState::Pending(tag) = self.extension_group {
self.extension_group = ExtensionGroupState::Active(tag);
}
return (encoder_scope)(self);
}

let mut encoder = Self::new(self.config);

(encoder_scope)(&mut encoder)?;
Expand All @@ -730,6 +750,14 @@ impl crate::Encoder<'_> for Encoder {
C: crate::types::Constructed<RC, EC>,
F: FnOnce(&mut Self::AnyEncoder<'b, 0, 0>) -> Result<(), Self::Error>,
{
if tag == Tag::SET && matches!(self.extension_group, ExtensionGroupState::Pending(_)) {
// Extension addition groups are encoded flattened: skip the SET wrapper once.
if let ExtensionGroupState::Pending(tag) = self.extension_group {
self.extension_group = ExtensionGroupState::Active(tag);
}
return (encoder_scope)(self);
}

let mut encoder = Self::new_set(self.config);

(encoder_scope)(&mut encoder)?;
Expand Down Expand Up @@ -757,13 +785,23 @@ impl crate::Encoder<'_> for Encoder {
/// Encode a extension addition group value.
fn encode_extension_addition_group<const RC: usize, const EC: usize, E>(
&mut self,
tag: Tag,
value: Option<&E>,
_: crate::types::Identifier,
) -> Result<Self::Ok, Self::Error>
where
E: Encode + crate::types::Constructed<RC, EC>,
{
value.encode(self)
match value {
Some(v) => {
let previous = self.extension_group;
self.extension_group = ExtensionGroupState::Pending(tag);
let result = v.encode(self);
self.extension_group = previous;
result
}
None => Ok(()),
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ pub trait Decoder<const RCL: usize = 0, const ECL: usize = 0>: Sized {
D: Decode + crate::types::Constructed<RC, EC>,
>(
&mut self,
tag: Tag,
) -> Result<Option<D>, Self::Error>;
}

Expand Down
1 change: 1 addition & 0 deletions src/enc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ pub trait Encoder<'encoder, const RCL: usize = 0, const ECL: usize = 0> {
/// `E` is the type of the extension addition group value being encoded.
fn encode_extension_addition_group<const RC: usize, const EC: usize, E>(
&mut self,
tag: Tag,
value: Option<&E>,
identifier: Identifier,
) -> Result<Self::Ok, Self::Error>
Expand Down
Loading
Loading