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