1 //! Context-specific field. 2 3 use crate::{ 4 asn1::AnyRef, Choice, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, Error, 5 Header, Length, Reader, Result, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, 6 }; 7 use core::cmp::Ordering; 8 9 /// Context-specific field which wraps an owned inner value. 10 /// 11 /// This type decodes/encodes a field which is specific to a particular context 12 /// and is identified by a [`TagNumber`]. 13 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 14 pub struct ContextSpecific<T> { 15 /// Context-specific tag number sans the leading `0b10000000` class 16 /// identifier bit and `0b100000` constructed flag. 17 pub tag_number: TagNumber, 18 19 /// Tag mode: `EXPLICIT` VS `IMPLICIT`. 20 pub tag_mode: TagMode, 21 22 /// Value of the field. 23 pub value: T, 24 } 25 26 impl<T> ContextSpecific<T> { 27 /// Attempt to decode an `EXPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the 28 /// provided [`TagNumber`]. 29 /// 30 /// This method has the following behavior which is designed to simplify 31 /// handling of extension fields, which are denoted in an ASN.1 schema 32 /// using the `...` ellipsis extension marker: 33 /// 34 /// - Skips over [`ContextSpecific`] fields with a tag number lower than 35 /// the current one, consuming and ignoring them. 36 /// - Returns `Ok(None)` if a [`ContextSpecific`] field with a higher tag 37 /// number is encountered. These fields are not consumed in this case, 38 /// allowing a field with a lower tag number to be omitted, then the 39 /// higher numbered field consumed as a follow-up. 40 /// - Returns `Ok(None)` if anything other than a [`ContextSpecific`] field 41 /// is encountered. decode_explicit<'a, R: Reader<'a>>( reader: &mut R, tag_number: TagNumber, ) -> Result<Option<Self>> where T: Decode<'a>,42 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 /// Attempt to decode an `IMPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the 53 /// provided [`TagNumber`]. 54 /// 55 /// This method otherwise behaves the same as `decode_explicit`, 56 /// but should be used in cases where the particular fields are `IMPLICIT` 57 /// as opposed to `EXPLICIT`. decode_implicit<'a, R: Reader<'a>>( reader: &mut R, tag_number: TagNumber, ) -> Result<Option<Self>> where T: DecodeValue<'a> + Tagged,58 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 /// Attempt to decode a context-specific field with the given 82 /// helper callback. decode_with<'a, F, R: Reader<'a>>( reader: &mut R, tag_number: TagNumber, f: F, ) -> Result<Option<Self>> where F: FnOnce(&mut R) -> Result<Self>,83 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 107 impl<'a, T> Choice<'a> for ContextSpecific<T> 108 where 109 T: Decode<'a> + Tagged, 110 { can_decode(tag: Tag) -> bool111 fn can_decode(tag: Tag) -> bool { 112 tag.is_context_specific() 113 } 114 } 115 116 impl<'a, T> Decode<'a> for ContextSpecific<T> 117 where 118 T: Decode<'a>, 119 { decode<R: Reader<'a>>(reader: &mut R) -> Result<Self>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 137 impl<T> EncodeValue for ContextSpecific<T> 138 where 139 T: EncodeValue + Tagged, 140 { value_len(&self) -> Result<Length>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 encode_value(&self, writer: &mut impl Writer) -> Result<()>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 156 impl<T> Tagged for ContextSpecific<T> 157 where 158 T: Tagged, 159 { tag(&self) -> Tag160 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 173 impl<'a, T> TryFrom<AnyRef<'a>> for ContextSpecific<T> 174 where 175 T: Decode<'a>, 176 { 177 type Error = Error; 178 try_from(any: AnyRef<'a>) -> Result<ContextSpecific<T>>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 194 impl<T> ValueOrd for ContextSpecific<T> 195 where 196 T: EncodeValue + ValueOrd + Tagged, 197 { value_cmp(&self, other: &Self) -> Result<Ordering>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 /// Context-specific field reference. 207 /// 208 /// This type encodes a field which is specific to a particular context 209 /// and is identified by a [`TagNumber`]. 210 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 211 pub struct ContextSpecificRef<'a, T> { 212 /// Context-specific tag number sans the leading `0b10000000` class 213 /// identifier bit and `0b100000` constructed flag. 214 pub tag_number: TagNumber, 215 216 /// Tag mode: `EXPLICIT` VS `IMPLICIT`. 217 pub tag_mode: TagMode, 218 219 /// Value of the field. 220 pub value: &'a T, 221 } 222 223 impl<'a, T> ContextSpecificRef<'a, T> { 224 /// Convert to a [`ContextSpecific`]. encoder(&self) -> ContextSpecific<EncodeValueRef<'a, T>>225 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 234 impl<'a, T> EncodeValue for ContextSpecificRef<'a, T> 235 where 236 T: EncodeValue + Tagged, 237 { value_len(&self) -> Result<Length>238 fn value_len(&self) -> Result<Length> { 239 self.encoder().value_len() 240 } 241 encode_value(&self, writer: &mut impl Writer) -> Result<()>242 fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { 243 self.encoder().encode_value(writer) 244 } 245 } 246 247 impl<'a, T> Tagged for ContextSpecificRef<'a, T> 248 where 249 T: Tagged, 250 { tag(&self) -> Tag251 fn tag(&self) -> Tag { 252 self.encoder().tag() 253 } 254 } 255 256 #[cfg(test)] 257 mod tests { 258 use super::ContextSpecific; 259 use crate::{asn1::BitStringRef, Decode, Encode, SliceReader, TagMode, TagNumber}; 260 use hex_literal::hex; 261 262 // Public key data from `pkcs8` crate's `ed25519-pkcs8-v2.der` 263 const EXAMPLE_BYTES: &[u8] = 264 &hex!("A123032100A3A7EAE3A8373830BC47E1167BC50E1DB551999651E0E2DC587623438EAC3F31"); 265 266 #[test] round_trip()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] context_specific_with_explicit_field()281 fn context_specific_with_explicit_field() { 282 let tag_number = TagNumber::new(0); 283 284 // Empty message 285 let mut reader = SliceReader::new(&[]).unwrap(); 286 assert_eq!( 287 ContextSpecific::<u8>::decode_explicit(&mut reader, tag_number).unwrap(), 288 None 289 ); 290 291 // Message containing a non-context-specific type 292 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 // Message containing an EXPLICIT context-specific field 299 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] context_specific_with_implicit_field()310 fn context_specific_with_implicit_field() { 311 // From RFC8410 Section 10.3: 312 // <https://datatracker.ietf.org/doc/html/rfc8410#section-10.3> 313 // 314 // 81 33: [1] 00 19 BF 44 09 69 84 CD FE 85 41 BA C1 67 DC 3B 315 // 96 C8 50 86 AA 30 B6 B6 CB 0C 5C 38 AD 70 31 66 316 // E1 317 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] context_specific_skipping_unknown_field()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] context_specific_returns_none_on_greater_tag_number()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 } 355