1use std::fmt;
2use std::cmp::Ordering;
3use std::hash::{Hash, Hasher};
4
5#[cfg(test)]
6use quickcheck::{Arbitrary, Gen};
7
8use crate::packet::Packet;
9
10#[derive(Clone, Copy, Debug)]
16#[non_exhaustive]
17pub enum Tag {
18 Reserved,
20 PKESK,
22 Signature,
24 SKESK,
26 OnePassSig,
28 SecretKey,
30 PublicKey,
32 SecretSubkey,
34 CompressedData,
36 SED,
38 Marker,
40 Literal,
42 Trust,
44 UserID,
46 PublicSubkey,
48 UserAttribute,
50 SEIP,
52 MDC,
54 AED,
56 Padding,
58 Unknown(u8),
60 Private(u8),
62}
63assert_send_and_sync!(Tag);
64
65impl Eq for Tag {}
66
67impl PartialEq for Tag {
68 fn eq(&self, other: &Tag) -> bool {
69 self.cmp(other) == Ordering::Equal
70 }
71}
72
73impl PartialOrd for Tag
74{
75 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
76 Some(self.cmp(other))
77 }
78}
79
80impl Ord for Tag
81{
82 fn cmp(&self, other: &Self) -> Ordering {
83 let a : u8 = (*self).into();
84 let b : u8 = (*other).into();
85 a.cmp(&b)
86 }
87}
88
89impl Hash for Tag {
90 fn hash<H: Hasher>(&self, state: &mut H) {
91 let t: u8 = (*self).into();
92 t.hash(state);
93 }
94}
95
96impl From<u8> for Tag {
97 fn from(u: u8) -> Self {
98 use crate::packet::Tag::*;
99
100 match u {
101 0 => Reserved,
102 1 => PKESK,
103 2 => Signature,
104 3 => SKESK,
105 4 => OnePassSig,
106 5 => SecretKey,
107 6 => PublicKey,
108 7 => SecretSubkey,
109 8 => CompressedData,
110 9 => SED,
111 10 => Marker,
112 11 => Literal,
113 12 => Trust,
114 13 => UserID,
115 14 => PublicSubkey,
116 17 => UserAttribute,
117 18 => SEIP,
118 19 => MDC,
119 20 => AED,
120 21 => Padding,
121 60..=63 => Private(u),
122 _ => Unknown(u),
123 }
124 }
125}
126
127impl From<Tag> for u8 {
128 fn from(t: Tag) -> u8 {
129 (&t).into()
130 }
131}
132
133impl From<&Tag> for u8 {
134 fn from(t: &Tag) -> u8 {
135 match t {
136 Tag::Reserved => 0,
137 Tag::PKESK => 1,
138 Tag::Signature => 2,
139 Tag::SKESK => 3,
140 Tag::OnePassSig => 4,
141 Tag::SecretKey => 5,
142 Tag::PublicKey => 6,
143 Tag::SecretSubkey => 7,
144 Tag::CompressedData => 8,
145 Tag::SED => 9,
146 Tag::Marker => 10,
147 Tag::Literal => 11,
148 Tag::Trust => 12,
149 Tag::UserID => 13,
150 Tag::PublicSubkey => 14,
151 Tag::UserAttribute => 17,
152 Tag::SEIP => 18,
153 Tag::MDC => 19,
154 Tag::AED => 20,
155 Tag::Padding => 21,
156 Tag::Private(x) => *x,
157 Tag::Unknown(x) => *x,
158 }
159 }
160}
161
162impl From<&Packet> for Tag {
163 fn from(p: &Packet) -> Tag {
164 p.tag()
165 }
166}
167
168impl From<Packet> for Tag {
169 fn from(p: Packet) -> Tag {
170 p.tag()
171 }
172}
173
174impl fmt::Display for Tag {
175 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176 match *self {
177 Tag::Reserved =>
178 f.write_str("Reserved - a packet tag MUST NOT have this value"),
179 Tag::PKESK =>
180 f.write_str("Public-Key Encrypted Session Key Packet"),
181 Tag::Signature =>
182 f.write_str("Signature Packet"),
183 Tag::SKESK =>
184 f.write_str("Symmetric-Key Encrypted Session Key Packet"),
185 Tag::OnePassSig =>
186 f.write_str("One-Pass Signature Packet"),
187 Tag::SecretKey =>
188 f.write_str("Secret-Key Packet"),
189 Tag::PublicKey =>
190 f.write_str("Public-Key Packet"),
191 Tag::SecretSubkey =>
192 f.write_str("Secret-Subkey Packet"),
193 Tag::CompressedData =>
194 f.write_str("Compressed Data Packet"),
195 Tag::SED =>
196 f.write_str("Symmetrically Encrypted Data Packet"),
197 Tag::Marker =>
198 f.write_str("Marker Packet"),
199 Tag::Literal =>
200 f.write_str("Literal Data Packet"),
201 Tag::Trust =>
202 f.write_str("Trust Packet"),
203 Tag::UserID =>
204 f.write_str("User ID Packet"),
205 Tag::PublicSubkey =>
206 f.write_str("Public-Subkey Packet"),
207 Tag::UserAttribute =>
208 f.write_str("User Attribute Packet"),
209 Tag::SEIP =>
210 f.write_str("Sym. Encrypted and Integrity Protected Data Packet"),
211 Tag::MDC =>
212 f.write_str("Modification Detection Code Packet"),
213 Tag::AED =>
214 f.write_str("AEAD Encrypted Data Packet"),
215 Tag::Padding =>
216 f.write_str("Padding Packet"),
217 Tag::Private(u) =>
218 f.write_fmt(format_args!("Private/Experimental Packet {}", u)),
219 Tag::Unknown(u) =>
220 f.write_fmt(format_args!("Unknown Packet {}", u)),
221 }
222 }
223}
224
225const PACKET_TAG_VARIANTS: [Tag; 19] = [
226 Tag::PKESK,
227 Tag::Signature,
228 Tag::SKESK,
229 Tag::OnePassSig,
230 Tag::SecretKey,
231 Tag::PublicKey,
232 Tag::SecretSubkey,
233 Tag::CompressedData,
234 Tag::SED,
235 Tag::Marker,
236 Tag::Literal,
237 Tag::Trust,
238 Tag::UserID,
239 Tag::PublicSubkey,
240 Tag::UserAttribute,
241 Tag::SEIP,
242 Tag::MDC,
243 Tag::AED,
244 Tag::Padding,
245];
246
247#[cfg(test)]
248impl Arbitrary for Tag {
249 fn arbitrary(g: &mut Gen) -> Self {
250 loop {
251 match u8::arbitrary(g) {
252 n @ 0..=63 => break n.into(),
253 _ => (), }
255 }
256 }
257}
258
259impl Tag {
260 pub fn is_critical(&self) -> bool {
269 match u8::from(self) {
270 0..=39 => true,
271 40..=63 => false,
272 64..=255 => true,
275 }
276 }
277
278 pub fn valid_start_of_message(&self) -> bool {
297 *self == Tag::PublicKey || *self == Tag::SecretKey
299 || *self == Tag::PKESK || *self == Tag::SKESK
301 || *self == Tag::Literal || *self == Tag::CompressedData
302 || *self == Tag::OnePassSig
304 || *self == Tag::Signature
306 }
307
308 pub fn variants() -> impl Iterator<Item=Tag> {
314 PACKET_TAG_VARIANTS.iter().cloned()
315 }
316}
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321
322 quickcheck! {
323 fn roundtrip(tag: Tag) -> bool {
324 let val: u8 = tag.into();
325 tag == Tag::from(val)
326 }
327 }
328
329 quickcheck! {
330 fn display(tag: Tag) -> bool {
331 let s = format!("{}", tag);
332 !s.is_empty()
333 }
334 }
335
336 quickcheck! {
337 fn unknown_private(tag: Tag) -> bool {
338 match tag {
339 Tag::Unknown(u) => u > 19 || u == 15 || u == 16,
340 Tag::Private(u) => (60..=63).contains(&u),
341 _ => true
342 }
343 }
344 }
345
346 #[test]
347 fn parse() {
348 for i in 0..u8::MAX {
349 let _ = Tag::from(i);
350 }
351 }
352
353 #[test]
354 fn tag_variants() {
355 use std::collections::HashSet;
356 use std::iter::FromIterator;
357
358 let derived_variants = (0..=u8::MAX)
361 .map(Tag::from)
362 .filter(|t| {
363 match t {
364 Tag::Reserved => false,
365 Tag::Private(_) => false,
366 Tag::Unknown(_) => false,
367 _ => true,
368 }
369 })
370 .collect::<HashSet<_>>();
371
372 let known_variants
373 = HashSet::from_iter(PACKET_TAG_VARIANTS.iter().cloned());
374
375 let missing = known_variants
376 .symmetric_difference(&derived_variants)
377 .collect::<Vec<_>>();
378
379 assert!(missing.is_empty(), "{:?}", missing);
380 }
381}