Skip to content

Commit 162207a

Browse files
committed
fix(ber,jer): handle extension groups correctly
- Adjust BER/JER encode/decode logic for extension groups - Update extension group tests
1 parent 6bd089b commit 162207a

7 files changed

Lines changed: 254 additions & 109 deletions

File tree

src/ber.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@ mod rules;
88
pub use identifier::Identifier;
99
pub(crate) use rules::EncodingRules;
1010

11+
#[derive(Clone, Copy, Debug)]
12+
pub(crate) enum ExtensionGroupState {
13+
None,
14+
Pending(crate::types::Tag),
15+
Active(crate::types::Tag),
16+
}
17+
18+
impl ExtensionGroupState {
19+
pub(crate) fn base_tag(self) -> Option<crate::types::Tag> {
20+
match self {
21+
Self::Pending(tag) | Self::Active(tag) => Some(tag),
22+
Self::None => None,
23+
}
24+
}
25+
}
26+
1127
/// Attempts to decode `T` from `input` using BER.
1228
/// # Errors
1329
/// Returns error specific to BER decoder if decoding is not possible.

src/ber/de.rs

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
mod config;
44
pub(super) mod parser;
55

6-
use super::identifier::Identifier;
6+
use super::{identifier::Identifier, ExtensionGroupState};
77
use crate::{
88
types::{
99
self,
@@ -29,6 +29,7 @@ pub struct Decoder<'input> {
2929
input: &'input [u8],
3030
config: DecoderOptions,
3131
initial_len: usize,
32+
extension_group: ExtensionGroupState,
3233
}
3334

3435
impl<'input> Decoder<'input> {
@@ -49,9 +50,14 @@ impl<'input> Decoder<'input> {
4950
input,
5051
config,
5152
initial_len: input.len(),
53+
extension_group: ExtensionGroupState::None,
5254
}
5355
}
5456

57+
fn translate_tag(&self, tag: Tag) -> Tag {
58+
tag.with_context_offset(self.extension_group.base_tag())
59+
}
60+
5561
/// Return a number of the decoded bytes by this decoder
5662
#[must_use]
5763
pub fn decoded_len(&self) -> usize {
@@ -85,6 +91,9 @@ impl<'input> Decoder<'input> {
8591
{
8692
return Ok(None);
8793
}
94+
95+
let tag = self.translate_tag(tag);
96+
8897
if tag != Tag::EOC {
8998
let upcoming_tag = self.peek_tag()?;
9099
if tag != upcoming_tag {
@@ -102,13 +111,15 @@ impl<'input> Decoder<'input> {
102111
}
103112

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

111121
pub(crate) fn parse_primitive_value(&mut self, tag: Tag) -> Result<(Identifier, &'input [u8])> {
122+
let tag = self.translate_tag(tag);
112123
let (input, (identifier, contents)) =
113124
self::parser::parse_value(self.config, self.input, Some(tag))?;
114125
self.input = input;
@@ -762,6 +773,28 @@ impl<'input> crate::Decoder for Decoder<'input> {
762773
default_initializer_fn: Option<DF>,
763774
decode_fn: F,
764775
) -> Result<D> {
776+
if tag == Tag::SEQUENCE && matches!(self.extension_group, ExtensionGroupState::Pending(_)) {
777+
// Extension addition groups are encoded flattened: skip the SEQUENCE wrapper once.
778+
if let ExtensionGroupState::Pending(tag) = self.extension_group {
779+
self.extension_group = ExtensionGroupState::Active(tag);
780+
}
781+
return if D::FIELDS.is_empty() && D::EXTENDED_FIELDS.is_none()
782+
|| (D::FIELDS.len() == D::FIELDS.number_of_optional_and_default_fields()
783+
&& self.input.is_empty())
784+
{
785+
if let Some(default_initializer_fn) = default_initializer_fn {
786+
Ok((default_initializer_fn)())
787+
} else {
788+
Err(DecodeError::from_kind(
789+
DecodeErrorKind::UnexpectedEmptyInput,
790+
self.codec(),
791+
))
792+
}
793+
} else {
794+
(decode_fn)(self)
795+
};
796+
}
797+
765798
self.parse_constructed_contents(tag, true, |decoder| {
766799
// If there are no fields, or the input is empty and we know that
767800
// all fields are optional or default fields, we call the default
@@ -806,7 +839,7 @@ impl<'input> crate::Decoder for Decoder<'input> {
806839
D: Fn(&mut Self, usize, Tag) -> Result<FIELDS, Self::Error>,
807840
F: FnOnce(Vec<FIELDS>) -> Result<SET, Self::Error>,
808841
{
809-
self.parse_constructed_contents(tag, true, |decoder| {
842+
let collect_fields = |decoder: &mut Self| -> Result<Vec<FIELDS>, Self::Error> {
810843
let mut fields = Vec::new();
811844

812845
loop {
@@ -823,6 +856,20 @@ impl<'input> crate::Decoder for Decoder<'input> {
823856
}
824857
}
825858

859+
Ok(fields)
860+
};
861+
862+
if tag == Tag::SET && matches!(self.extension_group, ExtensionGroupState::Pending(_)) {
863+
// Extension addition groups are encoded flattened: skip the SET wrapper once.
864+
if let ExtensionGroupState::Pending(tag) = self.extension_group {
865+
self.extension_group = ExtensionGroupState::Active(tag);
866+
}
867+
let fields = collect_fields(self)?;
868+
return (field_fn)(fields);
869+
}
870+
871+
self.parse_constructed_contents(tag, true, |decoder| {
872+
let fields = collect_fields(decoder)?;
826873
(field_fn)(fields)
827874
})
828875
}
@@ -897,9 +944,26 @@ impl<'input> crate::Decoder for Decoder<'input> {
897944
D: Decode + crate::types::Constructed<RL, EL>,
898945
>(
899946
&mut self,
900-
_tag: Tag,
947+
tag: Tag,
901948
) -> Result<Option<D>, Self::Error> {
902-
<Option<D>>::decode(self)
949+
if self.input.is_empty() {
950+
return Ok(None);
951+
}
952+
953+
let (_, identifier) = parser::parse_identifier_octet(self.input).map_err(|e| match e {
954+
ParseNumberError::Nom(e) => DecodeError::map_nom_err(e, self.codec()),
955+
ParseNumberError::Overflow => DecodeError::integer_overflow(32u32, self.codec()),
956+
})?;
957+
958+
if identifier.tag == tag {
959+
let previous = self.extension_group;
960+
self.extension_group = ExtensionGroupState::Pending(tag);
961+
let result = D::decode(self).map(Some);
962+
self.extension_group = previous;
963+
result
964+
} else {
965+
Ok(None)
966+
}
903967
}
904968
}
905969

src/ber/enc.rs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ mod config;
55
use alloc::{borrow::ToOwned, collections::VecDeque, string::ToString, vec::Vec};
66
use chrono::Timelike;
77

8-
use super::Identifier;
8+
use super::{ExtensionGroupState, Identifier};
99
use crate::{
1010
bits::octet_string_ascending,
1111
types::{
@@ -28,6 +28,7 @@ pub struct Encoder {
2828
config: EncoderOptions,
2929
is_set_encoding: bool,
3030
set_buffer: alloc::collections::BTreeMap<Tag, Vec<u8>>,
31+
extension_group: ExtensionGroupState,
3132
}
3233

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

@@ -63,6 +65,7 @@ impl Encoder {
6365
is_set_encoding: true,
6466
output: <_>::default(),
6567
set_buffer: <_>::default(),
68+
extension_group: ExtensionGroupState::None,
6669
}
6770
}
6871

@@ -78,9 +81,14 @@ impl Encoder {
7881
config,
7982
is_set_encoding: false,
8083
set_buffer: <_>::default(),
84+
extension_group: ExtensionGroupState::None,
8185
}
8286
}
8387

88+
fn translate_tag(&self, tag: Tag) -> Tag {
89+
tag.with_context_offset(self.extension_group.base_tag())
90+
}
91+
8492
/// Consumes the encoder and returns the output of the encoding.
8593
#[must_use]
8694
pub fn output(self) -> Vec<u8> {
@@ -243,6 +251,10 @@ impl Encoder {
243251

244252
/// Encodes a given ASN.1 BER value with the `identifier`.
245253
fn encode_value(&mut self, identifier: Identifier, value: &[u8]) {
254+
let identifier = Identifier::from_tag(
255+
self.translate_tag(identifier.tag),
256+
identifier.is_constructed,
257+
);
246258
let ident_bytes = self.encode_identifier(identifier);
247259
self.append_byte_or_bytes(ident_bytes);
248260
self.encode_length(identifier, value);
@@ -711,6 +723,14 @@ impl crate::Encoder<'_> for Encoder {
711723
C: crate::types::Constructed<RC, EC>,
712724
F: FnOnce(&mut Self::AnyEncoder<'b, 0, 0>) -> Result<(), Self::Error>,
713725
{
726+
if tag == Tag::SEQUENCE && matches!(self.extension_group, ExtensionGroupState::Pending(_)) {
727+
// Extension addition groups are encoded flattened: skip the SEQUENCE wrapper once.
728+
if let ExtensionGroupState::Pending(tag) = self.extension_group {
729+
self.extension_group = ExtensionGroupState::Active(tag);
730+
}
731+
return (encoder_scope)(self);
732+
}
733+
714734
let mut encoder = Self::new(self.config);
715735

716736
(encoder_scope)(&mut encoder)?;
@@ -730,6 +750,14 @@ impl crate::Encoder<'_> for Encoder {
730750
C: crate::types::Constructed<RC, EC>,
731751
F: FnOnce(&mut Self::AnyEncoder<'b, 0, 0>) -> Result<(), Self::Error>,
732752
{
753+
if tag == Tag::SET && matches!(self.extension_group, ExtensionGroupState::Pending(_)) {
754+
// Extension addition groups are encoded flattened: skip the SET wrapper once.
755+
if let ExtensionGroupState::Pending(tag) = self.extension_group {
756+
self.extension_group = ExtensionGroupState::Active(tag);
757+
}
758+
return (encoder_scope)(self);
759+
}
760+
733761
let mut encoder = Self::new_set(self.config);
734762

735763
(encoder_scope)(&mut encoder)?;
@@ -757,14 +785,23 @@ impl crate::Encoder<'_> for Encoder {
757785
/// Encode a extension addition group value.
758786
fn encode_extension_addition_group<const RC: usize, const EC: usize, E>(
759787
&mut self,
760-
_tag: Tag,
788+
tag: Tag,
761789
value: Option<&E>,
762790
_: crate::types::Identifier,
763791
) -> Result<Self::Ok, Self::Error>
764792
where
765793
E: Encode + crate::types::Constructed<RC, EC>,
766794
{
767-
value.encode(self)
795+
match value {
796+
Some(v) => {
797+
let previous = self.extension_group;
798+
self.extension_group = ExtensionGroupState::Pending(tag);
799+
let result = v.encode(self);
800+
self.extension_group = previous;
801+
result
802+
}
803+
None => Ok(()),
804+
}
768805
}
769806
}
770807

src/jer/de.rs

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ impl crate::Decoder for Decoder {
179179
F: FnOnce(&mut Self) -> Result<D, Self::Error>,
180180
{
181181
let mut last = self.stack.pop().ok_or_else(JerDecodeErrorKind::eoi)?;
182-
let value_map = last
182+
let _ = last
183183
.as_object_mut()
184184
.ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
185185
needed: "object",
@@ -193,12 +193,24 @@ impl crate::Decoder for Decoder {
193193
field_names.extend(extended_fields.iter().map(|f| f.name));
194194
}
195195
field_names.reverse();
196+
// Push the (now partially consumed) object onto the stack so extension-addition-group
197+
// decoding can pull group fields from the same flattened object.
198+
self.stack.push(last);
199+
let scope_index = self.stack.len() - 1;
196200
for name in field_names {
197-
self.stack
198-
.push(value_map.remove(name).unwrap_or(Value::Null));
201+
let value = self
202+
.stack
203+
.get_mut(scope_index)
204+
.and_then(|v| v.as_object_mut())
205+
.and_then(|obj| obj.remove(name))
206+
.unwrap_or(Value::Null);
207+
self.stack.push(value);
199208
}
200209

201-
(decode_fn)(self)
210+
let result = (decode_fn)(self);
211+
// Pop the scope object frame.
212+
let _ = self.stack.pop();
213+
result
202214
}
203215

204216
fn decode_sequence_of<D: crate::Decode>(
@@ -478,7 +490,51 @@ impl crate::Decoder for Decoder {
478490
&mut self,
479491
_tag: Tag,
480492
) -> Result<Option<D>, Self::Error> {
481-
self.decode_optional()
493+
// The SEQUENCE decoder pushes a placeholder for the extension group field (which is not
494+
// explicitly present in JER because extension groups are flattened).
495+
//
496+
// We decode a group by extracting only the group's fields from the current object and
497+
// decoding the group from that scoped object.
498+
let _ = self.stack.pop().ok_or_else(JerDecodeErrorKind::eoi)?;
499+
500+
let index = self
501+
.stack
502+
.iter()
503+
.rposition(|v| v.is_object())
504+
.ok_or_else(JerDecodeErrorKind::eoi)?;
505+
let obj = self
506+
.stack
507+
.get_mut(index)
508+
.and_then(|v| v.as_object_mut())
509+
.ok_or_else(|| JerDecodeErrorKind::TypeMismatch {
510+
needed: "object",
511+
found: "unknown".into(),
512+
})?;
513+
514+
let mut group_obj = serde_json::Map::with_capacity(
515+
D::FIELDS.len() + D::EXTENDED_FIELDS.as_ref().map_or(0, |fields| fields.len()),
516+
);
517+
let mut is_present = false;
518+
for field in D::FIELDS.iter() {
519+
if let Some(value) = obj.remove(field.name) {
520+
is_present |= !value.is_null();
521+
group_obj.insert(alloc::string::String::from(field.name), value);
522+
}
523+
}
524+
if let Some(extended_fields) = D::EXTENDED_FIELDS {
525+
for field in extended_fields.iter() {
526+
if let Some(value) = obj.remove(field.name) {
527+
is_present |= !value.is_null();
528+
group_obj.insert(alloc::string::String::from(field.name), value);
529+
}
530+
}
531+
}
532+
if is_present {
533+
self.stack.push(Value::Object(group_obj));
534+
D::decode(self).map(Some)
535+
} else {
536+
Ok(None)
537+
}
482538
}
483539

484540
fn codec(&self) -> crate::Codec {

src/jer/enc.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,9 +536,22 @@ impl crate::Encoder<'_> for Encoder {
536536
where
537537
E: crate::Encode + crate::types::Constructed<RL, EL>,
538538
{
539+
self.stack.pop();
539540
match value {
540-
Some(v) => v.encode(self),
541-
None => self.encode_none::<E>(Identifier::EMPTY),
541+
Some(v) => {
542+
let mut inner = Self::new();
543+
v.encode(&mut inner)?;
544+
if let Value::Object(obj) = inner.to_json()? {
545+
self.constructed_stack
546+
.last_mut()
547+
.ok_or_else(|| JerEncodeErrorKind::JsonEncoder {
548+
msg: "Internal stack mismatch!".into(),
549+
})?
550+
.extend(obj);
551+
}
552+
Ok(())
553+
}
554+
None => Ok(()),
542555
}
543556
}
544557

0 commit comments

Comments
 (0)