1use crate::{
4 asn1::AnyRef, Choice, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, Error,
5 Header, Length, Reader, Result, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer,
6};
7use core::cmp::Ordering;
8
9#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
14pub struct ContextSpecific<T> {
15 pub tag_number: TagNumber,
18
19 pub tag_mode: TagMode,
21
22 pub value: T,
24}
25
26impl<T> ContextSpecific<T> {
27 pub fn decode_explicit<'a, R: Reader<'a>>(
43 reader: &mut R,
44 tag_number: TagNumber,
45 ) -> Result<Option<Self>>
46 where
47 T: Decode<'a>,
48 {
49 Self::decode_with(reader, tag_number, |reader| Self::decode(reader))
50 }
51
52 pub fn decode_implicit<'a, R: Reader<'a>>(
59 reader: &mut R,
60 tag_number: TagNumber,
61 ) -> Result<Option<Self>>
62 where
63 T: DecodeValue<'a> + Tagged,
64 {
65 Self::decode_with(reader, tag_number, |reader| {
66 let header = Header::decode(reader)?;
67 let value = T::decode_value(reader, header)?;
68
69 if header.tag.is_constructed() != value.tag().is_constructed() {
70 return Err(header.tag.non_canonical_error());
71 }
72
73 Ok(Self {
74 tag_number,
75 tag_mode: TagMode::Implicit,
76 value,
77 })
78 })
79 }
80
81 fn decode_with<'a, F, R: Reader<'a>>(
84 reader: &mut R,
85 tag_number: TagNumber,
86 f: F,
87 ) -> Result<Option<Self>>
88 where
89 F: FnOnce(&mut R) -> Result<Self>,
90 {
91 while let Some(octet) = reader.peek_byte() {
92 let tag = Tag::try_from(octet)?;
93
94 if !tag.is_context_specific() || (tag.number() > tag_number) {
95 break;
96 } else if tag.number() == tag_number {
97 return Some(f(reader)).transpose();
98 } else {
99 AnyRef::decode(reader)?;
100 }
101 }
102
103 Ok(None)
104 }
105}
106
107impl<'a, T> Choice<'a> for ContextSpecific<T>
108where
109 T: Decode<'a> + Tagged,
110{
111 fn can_decode(tag: Tag) -> bool {
112 tag.is_context_specific()
113 }
114}
115
116impl<'a, T> Decode<'a> for ContextSpecific<T>
117where
118 T: Decode<'a>,
119{
120 fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Self> {
121 let header = Header::decode(reader)?;
122
123 match header.tag {
124 Tag::ContextSpecific {
125 number,
126 constructed: true,
127 } => Ok(Self {
128 tag_number: number,
129 tag_mode: TagMode::default(),
130 value: reader.read_nested(header.length, |reader| T::decode(reader))?,
131 }),
132 tag => Err(tag.unexpected_error(None)),
133 }
134 }
135}
136
137impl<T> EncodeValue for ContextSpecific<T>
138where
139 T: EncodeValue + Tagged,
140{
141 fn value_len(&self) -> Result<Length> {
142 match self.tag_mode {
143 TagMode::Explicit => self.value.encoded_len(),
144 TagMode::Implicit => self.value.value_len(),
145 }
146 }
147
148 fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
149 match self.tag_mode {
150 TagMode::Explicit => self.value.encode(writer),
151 TagMode::Implicit => self.value.encode_value(writer),
152 }
153 }
154}
155
156impl<T> Tagged for ContextSpecific<T>
157where
158 T: Tagged,
159{
160 fn tag(&self) -> Tag {
161 let constructed = match self.tag_mode {
162 TagMode::Explicit => true,
163 TagMode::Implicit => self.value.tag().is_constructed(),
164 };
165
166 Tag::ContextSpecific {
167 number: self.tag_number,
168 constructed,
169 }
170 }
171}
172
173impl<'a, T> TryFrom<AnyRef<'a>> for ContextSpecific<T>
174where
175 T: Decode<'a>,
176{
177 type Error = Error;
178
179 fn try_from(any: AnyRef<'a>) -> Result<ContextSpecific<T>> {
180 match any.tag() {
181 Tag::ContextSpecific {
182 number,
183 constructed: true,
184 } => Ok(Self {
185 tag_number: number,
186 tag_mode: TagMode::default(),
187 value: T::from_der(any.value())?,
188 }),
189 tag => Err(tag.unexpected_error(None)),
190 }
191 }
192}
193
194impl<T> ValueOrd for ContextSpecific<T>
195where
196 T: EncodeValue + ValueOrd + Tagged,
197{
198 fn value_cmp(&self, other: &Self) -> Result<Ordering> {
199 match self.tag_mode {
200 TagMode::Explicit => self.der_cmp(other),
201 TagMode::Implicit => self.value_cmp(other),
202 }
203 }
204}
205
206#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
211pub struct ContextSpecificRef<'a, T> {
212 pub tag_number: TagNumber,
215
216 pub tag_mode: TagMode,
218
219 pub value: &'a T,
221}
222
223impl<'a, T> ContextSpecificRef<'a, T> {
224 fn encoder(&self) -> ContextSpecific<EncodeValueRef<'a, T>> {
226 ContextSpecific {
227 tag_number: self.tag_number,
228 tag_mode: self.tag_mode,
229 value: EncodeValueRef(self.value),
230 }
231 }
232}
233
234impl<'a, T> EncodeValue for ContextSpecificRef<'a, T>
235where
236 T: EncodeValue + Tagged,
237{
238 fn value_len(&self) -> Result<Length> {
239 self.encoder().value_len()
240 }
241
242 fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
243 self.encoder().encode_value(writer)
244 }
245}
246
247impl<'a, T> Tagged for ContextSpecificRef<'a, T>
248where
249 T: Tagged,
250{
251 fn tag(&self) -> Tag {
252 self.encoder().tag()
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use super::ContextSpecific;
259 use crate::{asn1::BitStringRef, Decode, Encode, SliceReader, TagMode, TagNumber};
260 use hex_literal::hex;
261
262 const EXAMPLE_BYTES: &[u8] =
264 &hex!("A123032100A3A7EAE3A8373830BC47E1167BC50E1DB551999651E0E2DC587623438EAC3F31");
265
266 #[test]
267 fn round_trip() {
268 let field = ContextSpecific::<BitStringRef<'_>>::from_der(EXAMPLE_BYTES).unwrap();
269 assert_eq!(field.tag_number.value(), 1);
270 assert_eq!(
271 field.value,
272 BitStringRef::from_bytes(&EXAMPLE_BYTES[5..]).unwrap()
273 );
274
275 let mut buf = [0u8; 128];
276 let encoded = field.encode_to_slice(&mut buf).unwrap();
277 assert_eq!(encoded, EXAMPLE_BYTES);
278 }
279
280 #[test]
281 fn context_specific_with_explicit_field() {
282 let tag_number = TagNumber::new(0);
283
284 let mut reader = SliceReader::new(&[]).unwrap();
286 assert_eq!(
287 ContextSpecific::<u8>::decode_explicit(&mut reader, tag_number).unwrap(),
288 None
289 );
290
291 let mut reader = SliceReader::new(&hex!("020100")).unwrap();
293 assert_eq!(
294 ContextSpecific::<u8>::decode_explicit(&mut reader, tag_number).unwrap(),
295 None
296 );
297
298 let mut reader = SliceReader::new(&hex!("A003020100")).unwrap();
300 let field = ContextSpecific::<u8>::decode_explicit(&mut reader, tag_number)
301 .unwrap()
302 .unwrap();
303
304 assert_eq!(field.tag_number, tag_number);
305 assert_eq!(field.tag_mode, TagMode::Explicit);
306 assert_eq!(field.value, 0);
307 }
308
309 #[test]
310 fn context_specific_with_implicit_field() {
311 let context_specific_implicit_bytes =
318 hex!("81210019BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6CB0C5C38AD703166E1");
319
320 let tag_number = TagNumber::new(1);
321
322 let mut reader = SliceReader::new(&context_specific_implicit_bytes).unwrap();
323 let field = ContextSpecific::<BitStringRef<'_>>::decode_implicit(&mut reader, tag_number)
324 .unwrap()
325 .unwrap();
326
327 assert_eq!(field.tag_number, tag_number);
328 assert_eq!(field.tag_mode, TagMode::Implicit);
329 assert_eq!(
330 field.value.as_bytes().unwrap(),
331 &context_specific_implicit_bytes[3..]
332 );
333 }
334
335 #[test]
336 fn context_specific_skipping_unknown_field() {
337 let tag = TagNumber::new(1);
338 let mut reader = SliceReader::new(&hex!("A003020100A103020101")).unwrap();
339 let field = ContextSpecific::<u8>::decode_explicit(&mut reader, tag)
340 .unwrap()
341 .unwrap();
342 assert_eq!(field.value, 1);
343 }
344
345 #[test]
346 fn context_specific_returns_none_on_greater_tag_number() {
347 let tag = TagNumber::new(0);
348 let mut reader = SliceReader::new(&hex!("A103020101")).unwrap();
349 assert_eq!(
350 ContextSpecific::<u8>::decode_explicit(&mut reader, tag).unwrap(),
351 None
352 );
353 }
354}