1 use serde::de;
2 use std::fmt;
3 
4 #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
5 pub struct Tag(u8);
6 
7 impl Tag {
8     pub const BOOLEAN: Self = Tag(0x01);
9     pub const INTEGER: Self = Tag(0x02);
10     pub const BIT_STRING: Self = Tag(0x03);
11     pub const OCTET_STRING: Self = Tag(0x04);
12     pub const NULL: Self = Tag(0x05);
13     pub const OID: Self = Tag(0x06);
14     pub const REAL: Self = Tag(0x09);
15     pub const UTF8_STRING: Self = Tag(0x0C);
16     pub const RELATIVE_OID: Self = Tag(0xD);
17     pub const NUMERIC_STRING: Self = Tag(0x12);
18     pub const PRINTABLE_STRING: Self = Tag(0x13);
19     pub const TELETEX_STRING: Self = Tag(0x14);
20     pub const VIDEOTEX_STRING: Self = Tag(0x15);
21     pub const IA5_STRING: Self = Tag(0x16);
22     pub const UTC_TIME: Self = Tag(0x17);
23     pub const GENERALIZED_TIME: Self = Tag(0x18);
24     pub const SEQUENCE: Self = Tag(0x30);
25     pub const SET: Self = Tag(0x31);
26     pub const APP_0: Self = Tag::application(0);
27     pub const APP_1: Self = Tag::application(1);
28     pub const APP_2: Self = Tag::application(2);
29     pub const APP_3: Self = Tag::application(3);
30     pub const APP_4: Self = Tag::application(4);
31     pub const APP_5: Self = Tag::application(5);
32     pub const APP_6: Self = Tag::application(6);
33     pub const APP_7: Self = Tag::application(7);
34     pub const APP_8: Self = Tag::application(8);
35     pub const APP_9: Self = Tag::application(9);
36     pub const APP_10: Self = Tag::application(10);
37     pub const APP_11: Self = Tag::application(11);
38     pub const APP_12: Self = Tag::application(12);
39     pub const APP_13: Self = Tag::application(13);
40     pub const APP_14: Self = Tag::application(14);
41     pub const APP_15: Self = Tag::application(15);
42     pub const CTX_0: Self = Tag::context_specific(0);
43     pub const CTX_1: Self = Tag::context_specific(1);
44     pub const CTX_2: Self = Tag::context_specific(2);
45     pub const CTX_3: Self = Tag::context_specific(3);
46     pub const CTX_4: Self = Tag::context_specific(4);
47     pub const CTX_5: Self = Tag::context_specific(5);
48     pub const CTX_6: Self = Tag::context_specific(6);
49     pub const CTX_7: Self = Tag::context_specific(7);
50     pub const CTX_8: Self = Tag::context_specific(8);
51     pub const CTX_9: Self = Tag::context_specific(9);
52     pub const CTX_10: Self = Tag::context_specific(10);
53     pub const CTX_11: Self = Tag::context_specific(11);
54     pub const CTX_12: Self = Tag::context_specific(12);
55     pub const CTX_13: Self = Tag::context_specific(13);
56     pub const CTX_14: Self = Tag::context_specific(14);
57     pub const CTX_15: Self = Tag::context_specific(15);
58 
59     #[inline]
application(number: u8) -> Self60     pub const fn application(number: u8) -> Self {
61         Tag(0xA0 | number)
62     }
63 
64     #[inline]
context_specific(number: u8) -> Self65     pub const fn context_specific(number: u8) -> Self {
66         Tag(0x80 | number)
67     }
68 
69     #[inline]
number(self) -> u870     pub const fn number(self) -> u8 {
71         self.0
72     }
73 
74     #[inline]
is_application(self) -> bool75     pub fn is_application(self) -> bool {
76         self.0 >= Self::APP_0.0 && self.0 <= Self::APP_15.0
77     }
78 
79     #[inline]
is_context_specific(self) -> bool80     pub fn is_context_specific(self) -> bool {
81         self.0 >= Self::CTX_0.0 && self.0 <= Self::CTX_15.0
82     }
83 }
84 
85 impl From<u8> for Tag {
from(tag: u8) -> Self86     fn from(tag: u8) -> Self {
87         Self(tag)
88     }
89 }
90 
91 impl fmt::Display for Tag {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result92     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93         match *self {
94             Tag::BOOLEAN => write!(f, "BOOLEAN"),
95             Tag::INTEGER => write!(f, "INTEGER"),
96             Tag::BIT_STRING => write!(f, "BIT STRING"),
97             Tag::OCTET_STRING => write!(f, "OCTET STRING"),
98             Tag::NULL => write!(f, "NULL"),
99             Tag::OID => write!(f, "OBJECT IDENTIFIER"),
100             Tag::REAL => write!(f, "REAL"),
101             Tag::UTF8_STRING => write!(f, "UTF8String"),
102             Tag::RELATIVE_OID => write!(f, "RELATIVE-OID"),
103             Tag::NUMERIC_STRING => write!(f, "NumericString"),
104             Tag::PRINTABLE_STRING => write!(f, "PrintableString"),
105             Tag::TELETEX_STRING => write!(f, "TeletexString"),
106             Tag::VIDEOTEX_STRING => write!(f, "VideotexString"),
107             Tag::IA5_STRING => write!(f, "IA5String"),
108             Tag::UTC_TIME => write!(f, "UTCTime"),
109             Tag::GENERALIZED_TIME => write!(f, "GeneralizedTime"),
110             Tag::SEQUENCE => write!(f, "SEQUENCE"),
111             Tag::SET => write!(f, "SET"),
112             Tag::APP_0 => write!(f, "ApplicationTag0"),
113             Tag::APP_1 => write!(f, "ApplicationTag1"),
114             Tag::APP_2 => write!(f, "ApplicationTag2"),
115             Tag::APP_3 => write!(f, "ApplicationTag3"),
116             Tag::APP_4 => write!(f, "ApplicationTag4"),
117             Tag::APP_5 => write!(f, "ApplicationTag5"),
118             Tag::APP_6 => write!(f, "ApplicationTag6"),
119             Tag::APP_7 => write!(f, "ApplicationTag7"),
120             Tag::APP_8 => write!(f, "ApplicationTag8"),
121             Tag::APP_9 => write!(f, "ApplicationTag9"),
122             Tag::APP_10 => write!(f, "ApplicationTag10"),
123             Tag::APP_11 => write!(f, "ApplicationTag11"),
124             Tag::APP_12 => write!(f, "ApplicationTag12"),
125             Tag::APP_13 => write!(f, "ApplicationTag13"),
126             Tag::APP_14 => write!(f, "ApplicationTag14"),
127             Tag::APP_15 => write!(f, "ApplicationTag15"),
128             Tag::CTX_0 => write!(f, "ContextTag0"),
129             Tag::CTX_1 => write!(f, "ContextTag1"),
130             Tag::CTX_2 => write!(f, "ContextTag2"),
131             Tag::CTX_3 => write!(f, "ContextTag3"),
132             Tag::CTX_4 => write!(f, "ContextTag4"),
133             Tag::CTX_5 => write!(f, "ContextTag5"),
134             Tag::CTX_6 => write!(f, "ContextTag6"),
135             Tag::CTX_7 => write!(f, "ContextTag7"),
136             Tag::CTX_8 => write!(f, "ContextTag8"),
137             Tag::CTX_9 => write!(f, "ContextTag9"),
138             Tag::CTX_10 => write!(f, "ContextTag10"),
139             Tag::CTX_11 => write!(f, "ContextTag11"),
140             Tag::CTX_12 => write!(f, "ContextTag12"),
141             Tag::CTX_13 => write!(f, "ContextTag13"),
142             Tag::CTX_14 => write!(f, "ContextTag14"),
143             Tag::CTX_15 => write!(f, "ContextTag15"),
144             unknown => write!(f, "UNKNOWN({})", unknown.0),
145         }
146     }
147 }
148 
149 impl fmt::Debug for Tag {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result150     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151         write!(f, "Tag({}[{}])", self, self.0)
152     }
153 }
154 
155 /// Used to peek next tag by using `Deserializer::deserialize_identifier`.
156 ///
157 /// Can be used to implement ASN.1 Choice.
158 ///
159 /// # Examples
160 /// ```
161 /// use serde::de;
162 /// use picky_asn1::{
163 ///     wrapper::{IntegerAsn1, Utf8StringAsn1},
164 ///     tag::{Tag, TagPeeker},
165 /// };
166 /// use std::fmt;
167 ///
168 /// pub enum MyChoice {
169 ///     Integer(u32),
170 ///     Utf8String(String),
171 /// }
172 ///
173 /// impl<'de> de::Deserialize<'de> for MyChoice {
174 ///     fn deserialize<D>(deserializer: D) -> Result<Self, <D as de::Deserializer<'de>>::Error>
175 ///     where
176 ///         D: de::Deserializer<'de>,
177 ///     {
178 ///         struct Visitor;
179 ///
180 ///         impl<'de> de::Visitor<'de> for Visitor {
181 ///             type Value = MyChoice;
182 ///
183 ///             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
184 ///                 formatter.write_str("a valid MyChoice")
185 ///             }
186 ///
187 ///             fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
188 ///             where
189 ///                 A: de::SeqAccess<'de>,
190 ///             {
191 ///                 match seq.next_element::<TagPeeker>()?.unwrap().next_tag {
192 ///                     Tag::INTEGER => {
193 ///                         let value = seq.next_element::<u32>()?.unwrap();
194 ///                         Ok(MyChoice::Integer(value))
195 ///                     }
196 ///                     Tag::UTF8_STRING => {
197 ///                         let value = seq.next_element::<String>()?.unwrap();
198 ///                         Ok(MyChoice::Utf8String(value))
199 ///                     }
200 ///                     _ => Err(de::Error::invalid_value(
201 ///                         de::Unexpected::Other(
202 ///                             "[MyChoice] unsupported or unknown choice value",
203 ///                         ),
204 ///                         &"a supported choice value",
205 ///                     ))
206 ///                 }
207 ///             }
208 ///         }
209 ///
210 ///         deserializer.deserialize_enum("MyChoice", &["Integer", "Utf8String"], Visitor)
211 ///     }
212 /// }
213 ///
214 /// let buffer = b"\x0C\x06\xE8\x8B\x97\xE5\xAD\x97";
215 /// let my_choice: MyChoice = picky_asn1_der::from_bytes(buffer).unwrap();
216 /// match my_choice {
217 ///     MyChoice::Integer(_) => panic!("wrong variant"),
218 ///     MyChoice::Utf8String(string) => assert_eq!(string, "苗字"),
219 /// }
220 /// ```
221 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
222 pub struct TagPeeker {
223     pub next_tag: Tag,
224 }
225 
226 impl<'de> de::Deserialize<'de> for TagPeeker {
deserialize<D>(deserializer: D) -> Result<TagPeeker, D::Error> where D: de::Deserializer<'de>,227     fn deserialize<D>(deserializer: D) -> Result<TagPeeker, D::Error>
228     where
229         D: de::Deserializer<'de>,
230     {
231         struct Visitor;
232 
233         impl<'de> de::Visitor<'de> for Visitor {
234             type Value = TagPeeker;
235 
236             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
237                 formatter.write_str("a valid ASN.1 tag")
238             }
239 
240             fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
241             where
242                 E: de::Error,
243             {
244                 Ok(TagPeeker { next_tag: v.into() })
245             }
246         }
247 
248         deserializer.deserialize_identifier(Visitor)
249     }
250 }
251