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