1
1
//! Context-specific field.
2
2
3
3
use crate :: {
4
- Choice , Decode , DecodeValue , DerOrd , Encode , EncodeValue , EncodeValueRef , Error , Header ,
4
+ Choice , Class , Decode , DecodeValue , DerOrd , Encode , EncodeValue , EncodeValueRef , Error , Header ,
5
5
Length , Reader , Tag , TagMode , TagNumber , Tagged , ValueOrd , Writer , asn1:: AnyRef ,
6
6
} ;
7
7
use core:: cmp:: Ordering ;
@@ -46,7 +46,10 @@ impl<T> ContextSpecific<T> {
46
46
where
47
47
T : Decode < ' a > ,
48
48
{
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) ?) )
50
53
}
51
54
52
55
/// Attempt to decode an `IMPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the
@@ -62,53 +65,54 @@ impl<T> ContextSpecific<T> {
62
65
where
63
66
T : DecodeValue < ' a > + Tagged ,
64
67
{
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) ?;
86
74
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 ( ) ) ;
106
84
}
107
85
108
- Ok ( None )
86
+ Ok ( Some ( Self {
87
+ tag_number,
88
+ tag_mode : TagMode :: Implicit ,
89
+ value,
90
+ } ) )
109
91
}
110
92
}
111
93
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
+
112
116
impl < ' a , T > Choice < ' a > for ContextSpecific < T >
113
117
where
114
118
T : Decode < ' a > + Tagged ,
@@ -131,6 +135,7 @@ where
131
135
match header. tag {
132
136
Tag :: ContextSpecific {
133
137
number,
138
+ // encoding shall be constructed
134
139
constructed : true ,
135
140
} => Ok ( Self {
136
141
tag_number : number,
@@ -170,7 +175,15 @@ where
170
175
{
171
176
fn tag ( & self ) -> Tag {
172
177
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].
173
181
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.
174
187
TagMode :: Implicit => self . value . tag ( ) . is_constructed ( ) ,
175
188
} ;
176
189
@@ -348,13 +361,11 @@ mod tests {
348
361
}
349
362
350
363
#[ test]
351
- fn context_specific_skipping_unknown_field ( ) {
364
+ fn context_specific_not_skipping_unknown_field ( ) {
352
365
let tag = TagNumber ( 1 ) ;
353
366
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 ) ;
358
369
}
359
370
360
371
#[ test]
0 commit comments