11//! Context-specific field.
22
33use crate :: {
4- Choice , Decode , DecodeValue , DerOrd , Encode , EncodeValue , EncodeValueRef , Error , Header ,
4+ Choice , Class , Decode , DecodeValue , DerOrd , Encode , EncodeValue , EncodeValueRef , Error , Header ,
55 Length , Reader , Tag , TagMode , TagNumber , Tagged , ValueOrd , Writer , asn1:: AnyRef ,
66} ;
77use core:: cmp:: Ordering ;
@@ -46,7 +46,10 @@ impl<T> ContextSpecific<T> {
4646 where
4747 T : Decode < ' a > ,
4848 {
49- Self :: decode_with ( reader, tag_number, |reader| Self :: decode ( reader) )
49+ if !peek_tag_matches ( reader, Class :: ContextSpecific , tag_number) ? {
50+ return Ok ( None ) ;
51+ }
52+ Ok ( Some ( Self :: decode ( reader) ?) )
5053 }
5154
5255 /// Attempt to decode an `IMPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the
@@ -62,53 +65,54 @@ impl<T> ContextSpecific<T> {
6265 where
6366 T : DecodeValue < ' a > + Tagged ,
6467 {
65- Self :: decode_with :: < _ , _ , T :: Error > ( reader, tag_number, |reader| {
66- // Decode IMPLICIT header
67- let header = Header :: decode ( reader) ?;
68-
69- // read_nested checks if header matches decoded length
70- let value = reader. read_nested ( header. length , |reader| {
71- // Decode inner IMPLICIT value
72- T :: decode_value ( reader, header)
73- } ) ?;
74-
75- if header. tag . is_constructed ( ) != value. tag ( ) . is_constructed ( ) {
76- return Err ( header. tag . non_canonical_error ( ) . into ( ) ) ;
77- }
78-
79- Ok ( Self {
80- tag_number,
81- tag_mode : TagMode :: Implicit ,
82- value,
83- } )
84- } )
85- }
68+ // Peek tag number
69+ if !peek_tag_matches :: < _ , T :: Error > ( reader, Class :: ContextSpecific , tag_number) ? {
70+ return Ok ( None ) ;
71+ }
72+ // Decode IMPLICIT header
73+ let header = Header :: decode ( reader) ?;
8674
87- /// Attempt to decode a context-specific field with the given
88- /// helper callback.
89- fn decode_with < ' a , F , R : Reader < ' a > , E > (
90- reader : & mut R ,
91- tag_number : TagNumber ,
92- f : F ,
93- ) -> Result < Option < Self > , E >
94- where
95- F : FnOnce ( & mut R ) -> Result < Self , E > ,
96- E : From < Error > ,
97- {
98- while let Some ( tag) = Tag :: peek_optional ( reader) ? {
99- if !tag. is_context_specific ( ) || ( tag. number ( ) > tag_number) {
100- break ;
101- } else if tag. number ( ) == tag_number {
102- return Some ( f ( reader) ) . transpose ( ) ;
103- } else {
104- AnyRef :: decode ( reader) ?;
105- }
75+ // read_nested checks if header matches decoded length
76+ let value = reader. read_nested ( header. length , |reader| {
77+ // Decode inner IMPLICIT value
78+ T :: decode_value ( reader, header)
79+ } ) ?;
80+
81+ // the encoding shall be constructed if the base encoding is constructed
82+ if header. tag . is_constructed ( ) != value. tag ( ) . is_constructed ( ) {
83+ return Err ( header. tag . non_canonical_error ( ) . into ( ) ) ;
10684 }
10785
108- Ok ( None )
86+ Ok ( Some ( Self {
87+ tag_number,
88+ tag_mode : TagMode :: Implicit ,
89+ value,
90+ } ) )
10991 }
11092}
11193
94+ /// Returns true if given context-specific (or any given class) field
95+ /// should be decoded, based on peeked tag.
96+ fn peek_tag_matches < ' a , R : Reader < ' a > , E > (
97+ reader : & mut R ,
98+ expected_class : Class ,
99+ expected_tag_number : TagNumber ,
100+ ) -> Result < bool , E >
101+ where
102+ E : From < Error > ,
103+ {
104+ // Peek tag or ignore end of stream
105+ let Some ( tag) = Tag :: peek_optional ( reader) ? else {
106+ return Ok ( false ) ;
107+ } ;
108+ // Ignore tags with different numbers
109+ if tag. class ( ) != expected_class || tag. number ( ) != expected_tag_number {
110+ return Ok ( false ) ;
111+ }
112+ // Tag matches
113+ Ok ( true )
114+ }
115+
112116impl < ' a , T > Choice < ' a > for ContextSpecific < T >
113117where
114118 T : Decode < ' a > + Tagged ,
@@ -131,6 +135,7 @@ where
131135 match header. tag {
132136 Tag :: ContextSpecific {
133137 number,
138+ // encoding shall be constructed
134139 constructed : true ,
135140 } => Ok ( Self {
136141 tag_number : number,
@@ -170,7 +175,15 @@ where
170175{
171176 fn tag ( & self ) -> Tag {
172177 let constructed = match self . tag_mode {
178+ // ISO/IEC 8825-1:2021
179+ // 8.14.3 If implicit tagging (see Rec. ITU-T X.680 | ISO/IEC 8824-1, 31.2.7) was not used in the definition of the type, the
180+ // encoding shall be constructed and the contents octets shall be the complete base encoding [Encode].
173181 TagMode :: Explicit => true ,
182+
183+ // ISO/IEC 8825-1:2021
184+ // 8.14.4 If implicit tagging was used in the definition of the type, then:
185+ // a) the encoding shall be constructed if the base encoding is constructed, and shall be primitive otherwise; and
186+ // b) the contents octets shall be the same as the contents octets [EncodeValue] of the base encoding.
174187 TagMode :: Implicit => self . value . tag ( ) . is_constructed ( ) ,
175188 } ;
176189
@@ -348,13 +361,11 @@ mod tests {
348361 }
349362
350363 #[ test]
351- fn context_specific_skipping_unknown_field ( ) {
364+ fn context_specific_not_skipping_unknown_field ( ) {
352365 let tag = TagNumber ( 1 ) ;
353366 let mut reader = SliceReader :: new ( & hex ! ( "A003020100A103020101" ) ) . unwrap ( ) ;
354- let field = ContextSpecific :: < u8 > :: decode_explicit ( & mut reader, tag)
355- . unwrap ( )
356- . unwrap ( ) ;
357- assert_eq ! ( field. value, 1 ) ;
367+ let field = ContextSpecific :: < u8 > :: decode_explicit ( & mut reader, tag) . unwrap ( ) ;
368+ assert_eq ! ( field, None ) ;
358369 }
359370
360371 #[ test]
0 commit comments