1 //! Context-specific field. 2 3 use crate::{ 4 asn1::Any, Choice, Decodable, Encodable, Encoder, Error, ErrorKind, Header, Length, Result, 5 Tag, TagNumber, 6 }; 7 use core::convert::TryFrom; 8 9 /// Context-specific field. 10 /// 11 /// This type encodes a field which is specific to a particular context, 12 /// and is identified by a [`TagNumber`]. 13 /// 14 /// Any context-specific field can be decoded/encoded with this type. 15 /// The intended use is to dynamically dispatch off of the context-specific 16 /// tag number when decoding, which allows support for extensions, which are 17 /// denoted in an ASN.1 schema using the `...` ellipsis extension marker. 18 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 19 pub struct ContextSpecific<'a> { 20 /// Context-specific tag number sans the leading `0b10000000` class 21 /// identifier bit and `0b100000` constructed flag. 22 pub tag_number: TagNumber, 23 24 /// Value of the field. 25 pub value: Any<'a>, 26 } 27 28 impl<'a> Choice<'a> for ContextSpecific<'a> { can_decode(tag: Tag) -> bool29 fn can_decode(tag: Tag) -> bool { 30 matches!(tag, Tag::ContextSpecific(_)) 31 } 32 } 33 34 impl<'a> Encodable for ContextSpecific<'a> { encoded_len(&self) -> Result<Length>35 fn encoded_len(&self) -> Result<Length> { 36 self.value.encoded_len()?.for_tlv() 37 } 38 encode(&self, encoder: &mut Encoder<'_>) -> Result<()>39 fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> { 40 let tag = Tag::ContextSpecific(self.tag_number); 41 Header::new(tag, self.value.encoded_len()?)?.encode(encoder)?; 42 self.value.encode(encoder) 43 } 44 } 45 46 impl<'a> From<&ContextSpecific<'a>> for ContextSpecific<'a> { from(value: &ContextSpecific<'a>) -> ContextSpecific<'a>47 fn from(value: &ContextSpecific<'a>) -> ContextSpecific<'a> { 48 *value 49 } 50 } 51 52 impl<'a> TryFrom<Any<'a>> for ContextSpecific<'a> { 53 type Error = Error; 54 try_from(any: Any<'a>) -> Result<ContextSpecific<'a>>55 fn try_from(any: Any<'a>) -> Result<ContextSpecific<'a>> { 56 match any.tag() { 57 Tag::ContextSpecific(tag_number) => Ok(Self { 58 tag_number, 59 value: Any::from_der(any.as_bytes())?, 60 }), 61 actual => Err(ErrorKind::UnexpectedTag { 62 expected: None, 63 actual, 64 } 65 .into()), 66 } 67 } 68 } 69 70 #[cfg(test)] 71 mod tests { 72 use super::ContextSpecific; 73 use crate::{Decodable, Encodable, Tag}; 74 use hex_literal::hex; 75 76 // Public key data from `pkcs8` crate's `ed25519-pkcs8-v2.der` 77 const EXAMPLE_BYTES: &[u8] = 78 &hex!("A123032100A3A7EAE3A8373830BC47E1167BC50E1DB551999651E0E2DC587623438EAC3F31"); 79 80 #[test] round_trip()81 fn round_trip() { 82 let field = ContextSpecific::from_der(EXAMPLE_BYTES).unwrap(); 83 assert_eq!(field.tag_number.value(), 1); 84 assert_eq!(field.value.tag(), Tag::BitString); 85 assert_eq!(field.value.as_bytes(), &EXAMPLE_BYTES[5..]); 86 87 let mut buf = [0u8; 128]; 88 let encoded = field.encode_to_slice(&mut buf).unwrap(); 89 assert_eq!(encoded, EXAMPLE_BYTES); 90 } 91 } 92