Skip to content

Commit ea038da

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 ea038da

5 files changed

Lines changed: 227 additions & 95 deletions

File tree

src/ber/de.rs

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub struct Decoder<'input> {
2929
input: &'input [u8],
3030
config: DecoderOptions,
3131
initial_len: usize,
32+
extension_group_base: Option<Tag>,
3233
}
3334

3435
impl<'input> Decoder<'input> {
@@ -49,6 +50,16 @@ impl<'input> Decoder<'input> {
4950
input,
5051
config,
5152
initial_len: input.len(),
53+
extension_group_base: None,
54+
}
55+
}
56+
57+
fn translate_tag(&self, tag: Tag) -> Tag {
58+
match self.extension_group_base {
59+
Some(base) if base.class == crate::types::Class::Context && tag.class == base.class => {
60+
Tag::new(tag.class, base.value.saturating_add(tag.value))
61+
}
62+
_ => tag,
5263
}
5364
}
5465

@@ -85,6 +96,9 @@ impl<'input> Decoder<'input> {
8596
{
8697
return Ok(None);
8798
}
99+
100+
let tag = self.translate_tag(tag);
101+
88102
if tag != Tag::EOC {
89103
let upcoming_tag = self.peek_tag()?;
90104
if tag != upcoming_tag {
@@ -102,13 +116,15 @@ impl<'input> Decoder<'input> {
102116
}
103117

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

111126
pub(crate) fn parse_primitive_value(&mut self, tag: Tag) -> Result<(Identifier, &'input [u8])> {
127+
let tag = self.translate_tag(tag);
112128
let (input, (identifier, contents)) =
113129
self::parser::parse_value(self.config, self.input, Some(tag))?;
114130
self.input = input;
@@ -762,6 +778,37 @@ impl<'input> crate::Decoder for Decoder<'input> {
762778
default_initializer_fn: Option<DF>,
763779
decode_fn: F,
764780
) -> Result<D> {
781+
if tag == Tag::SEQUENCE {
782+
if let Some(base) = self.extension_group_base.take() {
783+
// We are decoding an extension addition group: the group tag was
784+
// already matched by `decode_extension_addition_group`, and the
785+
// group's contents are encoded "flattened" (without the SEQUENCE
786+
// wrapper). Enable tag translation for the duration of decoding
787+
// this SEQUENCE value and restore afterwards.
788+
let previous = self.extension_group_base;
789+
self.extension_group_base = Some(base);
790+
791+
let result = if D::FIELDS.is_empty() && D::EXTENDED_FIELDS.is_none()
792+
|| (D::FIELDS.len() == D::FIELDS.number_of_optional_and_default_fields()
793+
&& self.input.is_empty())
794+
{
795+
if let Some(default_initializer_fn) = default_initializer_fn {
796+
Ok((default_initializer_fn)())
797+
} else {
798+
Err(DecodeError::from_kind(
799+
DecodeErrorKind::UnexpectedEmptyInput,
800+
self.codec(),
801+
))
802+
}
803+
} else {
804+
(decode_fn)(self)
805+
};
806+
807+
self.extension_group_base = previous;
808+
return result;
809+
}
810+
}
811+
765812
self.parse_constructed_contents(tag, true, |decoder| {
766813
// If there are no fields, or the input is empty and we know that
767814
// all fields are optional or default fields, we call the default
@@ -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_base;
960+
self.extension_group_base = Some(tag);
961+
let result = D::decode(self).map(Some);
962+
self.extension_group_base = previous;
963+
result
964+
} else {
965+
Ok(None)
966+
}
903967
}
904968
}
905969

src/ber/enc.rs

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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_base: Option<Tag>,
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_base: 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_base: None,
6669
}
6770
}
6871

@@ -78,6 +81,16 @@ impl Encoder {
7881
config,
7982
is_set_encoding: false,
8083
set_buffer: <_>::default(),
84+
extension_group_base: None,
85+
}
86+
}
87+
88+
fn translate_tag(&self, tag: Tag) -> Tag {
89+
match self.extension_group_base {
90+
Some(base) if base.class == crate::types::Class::Context && tag.class == base.class => {
91+
Tag::new(tag.class, base.value.saturating_add(tag.value))
92+
}
93+
_ => tag,
8194
}
8295
}
8396

@@ -243,6 +256,10 @@ impl Encoder {
243256

244257
/// Encodes a given ASN.1 BER value with the `identifier`.
245258
fn encode_value(&mut self, identifier: Identifier, value: &[u8]) {
259+
let identifier = Identifier::from_tag(
260+
self.translate_tag(identifier.tag),
261+
identifier.is_constructed,
262+
);
246263
let ident_bytes = self.encode_identifier(identifier);
247264
self.append_byte_or_bytes(ident_bytes);
248265
self.encode_length(identifier, value);
@@ -711,6 +728,16 @@ impl crate::Encoder<'_> for Encoder {
711728
C: crate::types::Constructed<RC, EC>,
712729
F: FnOnce(&mut Self::AnyEncoder<'b, 0, 0>) -> Result<(), Self::Error>,
713730
{
731+
if tag == Tag::SEQUENCE {
732+
if let Some(base) = self.extension_group_base.take() {
733+
let previous = self.extension_group_base;
734+
self.extension_group_base = Some(base);
735+
let result = (encoder_scope)(self);
736+
self.extension_group_base = previous;
737+
return result;
738+
}
739+
}
740+
714741
let mut encoder = Self::new(self.config);
715742

716743
(encoder_scope)(&mut encoder)?;
@@ -730,6 +757,16 @@ impl crate::Encoder<'_> for Encoder {
730757
C: crate::types::Constructed<RC, EC>,
731758
F: FnOnce(&mut Self::AnyEncoder<'b, 0, 0>) -> Result<(), Self::Error>,
732759
{
760+
if tag == Tag::SET {
761+
if let Some(base) = self.extension_group_base.take() {
762+
let previous = self.extension_group_base;
763+
self.extension_group_base = Some(base);
764+
let result = (encoder_scope)(self);
765+
self.extension_group_base = previous;
766+
return result;
767+
}
768+
}
769+
733770
let mut encoder = Self::new_set(self.config);
734771

735772
(encoder_scope)(&mut encoder)?;
@@ -757,14 +794,23 @@ impl crate::Encoder<'_> for Encoder {
757794
/// Encode a extension addition group value.
758795
fn encode_extension_addition_group<const RC: usize, const EC: usize, E>(
759796
&mut self,
760-
_tag: Tag,
797+
tag: Tag,
761798
value: Option<&E>,
762799
_: crate::types::Identifier,
763800
) -> Result<Self::Ok, Self::Error>
764801
where
765802
E: Encode + crate::types::Constructed<RC, EC>,
766803
{
767-
value.encode(self)
804+
match value {
805+
Some(v) => {
806+
let previous = self.extension_group_base;
807+
self.extension_group_base = Some(tag);
808+
let result = v.encode(self);
809+
self.extension_group_base = previous;
810+
result
811+
}
812+
None => Ok(()),
813+
}
768814
}
769815
}
770816

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)