1 use std::fmt;
2 use std::cmp::Ordering;
3 use std::hash::{Hash, Hasher};
4 
5 #[cfg(any(test, feature = "quickcheck"))]
6 use quickcheck::{Arbitrary, Gen};
7 
8 use crate::packet::Packet;
9 
10 /// The OpenPGP packet tags as defined in [Section 4.3 of RFC 4880].
11 ///
12 ///   [Section 4.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-4.3
13 ///
14 /// The values correspond to the serialized format.
15 #[derive(Clone, Copy, Debug)]
16 pub enum Tag {
17     /// Reserved Packet tag.
18     Reserved,
19     /// Public-Key Encrypted Session Key Packet.
20     PKESK,
21     /// Signature Packet.
22     Signature,
23     /// Symmetric-Key Encrypted Session Key Packet.
24     SKESK,
25     /// One-Pass Signature Packet.
26     OnePassSig,
27     /// Secret-Key Packet.
28     SecretKey,
29     /// Public-Key Packet.
30     PublicKey,
31     /// Secret-Subkey Packet.
32     SecretSubkey,
33     /// Compressed Data Packet.
34     CompressedData,
35     /// Symmetrically Encrypted Data Packet.
36     SED,
37     /// Marker Packet (Obsolete Literal Packet).
38     Marker,
39     /// Literal Data Packet.
40     Literal,
41     /// Trust Packet.
42     Trust,
43     /// User ID Packet.
44     UserID,
45     /// Public-Subkey Packet.
46     PublicSubkey,
47     /// User Attribute Packet.
48     UserAttribute,
49     /// Sym. Encrypted and Integrity Protected Data Packet.
50     SEIP,
51     /// Modification Detection Code Packet.
52     MDC,
53     /// AEAD Encrypted Data Packet.
54     ///
55     /// This feature is [experimental](../index.html#experimental-features).
56     AED,
57     /// Unassigned packets (as of RFC4880).
58     Unknown(u8),
59     /// Experimental packets.
60     Private(u8),
61 }
62 
63 impl Eq for Tag {}
64 
65 impl PartialEq for Tag {
eq(&self, other: &Tag) -> bool66     fn eq(&self, other: &Tag) -> bool {
67         self.cmp(other) == Ordering::Equal
68     }
69 }
70 
71 impl PartialOrd for Tag
72 {
partial_cmp(&self, other: &Self) -> Option<Ordering>73     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
74         Some(self.cmp(other))
75     }
76 }
77 
78 impl Ord for Tag
79 {
cmp(&self, other: &Self) -> Ordering80     fn cmp(&self, other: &Self) -> Ordering {
81         let a : u8 = (*self).into();
82         let b : u8 = (*other).into();
83         a.cmp(&b)
84     }
85 }
86 
87 impl Hash for Tag {
hash<H: Hasher>(&self, state: &mut H)88     fn hash<H: Hasher>(&self, state: &mut H) {
89         let t: u8 = (*self).into();
90         t.hash(state);
91     }
92 }
93 
94 impl From<u8> for Tag {
from(u: u8) -> Self95     fn from(u: u8) -> Self {
96         use crate::packet::Tag::*;
97 
98         match u {
99             0 => Reserved,
100             1 => PKESK,
101             2 => Signature,
102             3 => SKESK,
103             4 => OnePassSig,
104             5 => SecretKey,
105             6 => PublicKey,
106             7 => SecretSubkey,
107             8 => CompressedData,
108             9 => SED,
109             10 => Marker,
110             11 => Literal,
111             12 => Trust,
112             13 => UserID,
113             14 => PublicSubkey,
114             17 => UserAttribute,
115             18 => SEIP,
116             19 => MDC,
117             20 => AED,
118             60..=63 => Private(u),
119             _ => Unknown(u),
120         }
121     }
122 }
123 
124 impl From<Tag> for u8 {
from(t: Tag) -> u8125     fn from(t: Tag) -> u8 {
126         (&t).into()
127     }
128 }
129 
130 impl From<&Tag> for u8 {
from(t: &Tag) -> u8131     fn from(t: &Tag) -> u8 {
132         match t {
133             &Tag::Reserved => 0,
134             &Tag::PKESK => 1,
135             &Tag::Signature => 2,
136             &Tag::SKESK => 3,
137             &Tag::OnePassSig => 4,
138             &Tag::SecretKey => 5,
139             &Tag::PublicKey => 6,
140             &Tag::SecretSubkey => 7,
141             &Tag::CompressedData => 8,
142             &Tag::SED => 9,
143             &Tag::Marker => 10,
144             &Tag::Literal => 11,
145             &Tag::Trust => 12,
146             &Tag::UserID => 13,
147             &Tag::PublicSubkey => 14,
148             &Tag::UserAttribute => 17,
149             &Tag::SEIP => 18,
150             &Tag::MDC => 19,
151             &Tag::AED => 20,
152             &Tag::Private(x) => x,
153             &Tag::Unknown(x) => x,
154         }
155     }
156 }
157 
158 impl From<&Packet> for Tag {
from(p: &Packet) -> Tag159     fn from(p: &Packet) -> Tag {
160         p.tag()
161     }
162 }
163 
164 impl From<Packet> for Tag {
from(p: Packet) -> Tag165     fn from(p: Packet) -> Tag {
166         p.tag()
167     }
168 }
169 
170 impl fmt::Display for Tag {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result171     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
172         match *self {
173             Tag::Reserved =>
174                 f.write_str("Reserved - a packet tag MUST NOT have this value"),
175             Tag::PKESK =>
176                 f.write_str("Public-Key Encrypted Session Key Packet"),
177             Tag::Signature =>
178                 f.write_str("Signature Packet"),
179             Tag::SKESK =>
180                 f.write_str("Symmetric-Key Encrypted Session Key Packet"),
181             Tag::OnePassSig =>
182                 f.write_str("One-Pass Signature Packet"),
183             Tag::SecretKey =>
184                 f.write_str("Secret-Key Packet"),
185             Tag::PublicKey =>
186                 f.write_str("Public-Key Packet"),
187             Tag::SecretSubkey =>
188                 f.write_str("Secret-Subkey Packet"),
189             Tag::CompressedData =>
190                 f.write_str("Compressed Data Packet"),
191             Tag::SED =>
192                 f.write_str("Symmetrically Encrypted Data Packet"),
193             Tag::Marker =>
194                 f.write_str("Marker Packet"),
195             Tag::Literal =>
196                 f.write_str("Literal Data Packet"),
197             Tag::Trust =>
198                 f.write_str("Trust Packet"),
199             Tag::UserID =>
200                 f.write_str("User ID Packet"),
201             Tag::PublicSubkey =>
202                 f.write_str("Public-Subkey Packet"),
203             Tag::UserAttribute =>
204                 f.write_str("User Attribute Packet"),
205             Tag::SEIP =>
206                 f.write_str("Sym. Encrypted and Integrity Protected Data Packet"),
207             Tag::MDC =>
208                 f.write_str("Modification Detection Code Packet"),
209             Tag::AED =>
210                 f.write_str("AEAD Encrypted Data Packet"),
211             Tag::Private(u) =>
212                 f.write_fmt(format_args!("Private/Experimental Packet {}", u)),
213             Tag::Unknown(u) =>
214                 f.write_fmt(format_args!("Unknown Packet {}", u)),
215         }
216     }
217 }
218 
219 #[cfg(any(test, feature = "quickcheck"))]
220 impl Arbitrary for Tag {
arbitrary<G: Gen>(g: &mut G) -> Self221     fn arbitrary<G: Gen>(g: &mut G) -> Self {
222         u8::arbitrary(g).into()
223     }
224 }
225 
226 impl Tag {
227     /// Returns whether the `Tag` can be at the start of a valid
228     /// message.
229     ///
230     /// [Certs] can start with `PublicKey`, [TSKs] with a `SecretKey`.
231     ///
232     ///   [Certs]: https://tools.ietf.org/html/rfc4880#section-11.1
233     ///   [TSKs]: https://tools.ietf.org/html/rfc4880#section-11.2
234     ///
235     /// [Messages] start with a `OnePassSig`, `Signature` (old style
236     /// non-one pass signatures), `PKESK`, `SKESK`, `CompressedData`,
237     /// or `Literal`.
238     ///
239     ///   [Messages]: https://tools.ietf.org/html/rfc4880#section-11.3
240     ///
241     /// Signatures can standalone either as a [detached signature], a
242     /// third-party certification, or a revocation certificate.
243     ///
244     ///   [detached signature]: https://tools.ietf.org/html/rfc4880#section-11.3
valid_start_of_message(&self) -> bool245     pub fn valid_start_of_message(&self) -> bool {
246         // Cert
247         *self == Tag::PublicKey || *self == Tag::SecretKey
248             // Message.
249             || *self == Tag::PKESK || *self == Tag::SKESK
250             || *self == Tag::Literal || *self == Tag::CompressedData
251             // Signed message.
252             || *self == Tag::OnePassSig
253             // Standalone signature, old-style signature.
254             || *self == Tag::Signature
255     }
256 }
257 
258 #[cfg(test)]
259 mod tests {
260     use super::*;
261 
262     quickcheck! {
263         fn roundtrip(tag: Tag) -> bool {
264             let val: u8 = tag.into();
265             tag == Tag::from(val)
266         }
267     }
268 
269     quickcheck! {
270         fn display(tag: Tag) -> bool {
271             let s = format!("{}", tag);
272             !s.is_empty()
273         }
274     }
275 
276     quickcheck! {
277         fn unknown_private(tag: Tag) -> bool {
278             match tag {
279                 Tag::Unknown(u) => u > 19 || u == 15 || u == 16,
280                 Tag::Private(u) => u >= 60 && u <= 63,
281                 _ => true
282             }
283         }
284     }
285 
286     #[test]
parse()287     fn parse() {
288         for i in 0..0x100usize {
289             Tag::from(i as u8);
290         }
291     }
292 }
293