1 use std::fmt;
2 
3 #[cfg(any(test, feature = "quickcheck"))]
4 use quickcheck::{Arbitrary, Gen};
5 
6 use crate::Error;
7 use crate::Fingerprint;
8 use crate::Result;
9 
10 /// A short identifier for certificates and keys.
11 ///
12 /// A KeyID is a fingerprint fragment.  It identifies a public key,
13 /// but is easy to forge.  For more details about how a KeyID is
14 /// generated, see [Section 12.2 of RFC 4880].
15 ///
16 ///   [Section 12.2 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-12.2
17 ///
18 /// Note: This enum cannot be exhaustively matched to allow future
19 /// extensions.
20 #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
21 pub enum KeyID {
22     /// Lower 8 byte SHA-1 hash.
23     V4([u8;8]),
24     /// Used for holding keyids that we don't understand.  For
25     /// instance, we don't grok v3 keyids.  And, it is possible that
26     /// the Issuer subpacket contains the wrong number of bytes.
27     Invalid(Box<[u8]>),
28 
29     /// This marks this enum as non-exhaustive.  Do not use this
30     /// variant.
31     #[doc(hidden)] __Nonexhaustive,
32 }
33 
34 impl fmt::Display for KeyID {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result35     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36         write!(f, "{}", self.convert_to_string(true))
37     }
38 }
39 
40 impl fmt::Debug for KeyID {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result41     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
42         f.debug_tuple("KeyID")
43             .field(&self.to_string())
44             .finish()
45     }
46 }
47 
48 impl fmt::UpperHex for KeyID {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result49     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50         f.write_str(&self.convert_to_string(false))
51     }
52 }
53 
54 impl fmt::LowerHex for KeyID {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result55     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56         let mut hex = self.convert_to_string(false);
57         hex.make_ascii_lowercase();
58         f.write_str(&hex)
59     }
60 }
61 
62 impl std::str::FromStr for KeyID {
63     type Err = anyhow::Error;
64 
from_str(s: &str) -> std::result::Result<Self, Self::Err>65     fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
66         let bytes = crate::fmt::hex::decode_pretty(s)?;
67 
68         // A KeyID is exactly 8 bytes long.
69         if bytes.len() == 8 {
70             Ok(KeyID::from_bytes(&bytes[..]))
71         } else {
72             // Maybe a fingerprint was given.  Try to parse it and
73             // convert it to a KeyID.
74             Ok(s.parse::<Fingerprint>()?.into())
75         }
76     }
77 }
78 
79 impl From<KeyID> for Vec<u8> {
from(id: KeyID) -> Self80     fn from(id: KeyID) -> Self {
81         let mut r = Vec::with_capacity(8);
82         match id {
83             KeyID::V4(ref b) => r.extend_from_slice(b),
84             KeyID::Invalid(ref b) => r.extend_from_slice(b),
85             KeyID::__Nonexhaustive => unreachable!(),
86         }
87         r
88     }
89 }
90 
91 impl From<u64> for KeyID {
from(id: u64) -> Self92     fn from(id: u64) -> Self {
93         Self::new(id)
94     }
95 }
96 
97 impl From<[u8; 8]> for KeyID {
from(id: [u8; 8]) -> Self98     fn from(id: [u8; 8]) -> Self {
99         KeyID::from_bytes(&id[..])
100     }
101 }
102 
103 impl From<&Fingerprint> for KeyID {
from(fp: &Fingerprint) -> Self104     fn from(fp: &Fingerprint) -> Self {
105         match fp {
106             Fingerprint::V4(fp) =>
107                 KeyID::from_bytes(&fp[fp.len() - 8..]),
108             Fingerprint::Invalid(fp) => {
109                 KeyID::Invalid(fp.clone())
110             }
111             Fingerprint::__Nonexhaustive => unreachable!(),
112         }
113     }
114 }
115 
116 impl From<Fingerprint> for KeyID {
from(fp: Fingerprint) -> Self117     fn from(fp: Fingerprint) -> Self {
118         match fp {
119             Fingerprint::V4(fp) =>
120                 KeyID::from_bytes(&fp[fp.len() - 8..]),
121             Fingerprint::Invalid(fp) => {
122                 KeyID::Invalid(fp)
123             }
124             Fingerprint::__Nonexhaustive => unreachable!(),
125         }
126     }
127 }
128 
129 impl KeyID {
130     /// Converts a u64 to a KeyID.
new(data: u64) -> KeyID131     pub fn new(data: u64) -> KeyID {
132         let bytes = data.to_be_bytes();
133         Self::from_bytes(&bytes[..])
134     }
135 
136     /// Converts the KeyID to a u64 if possible.
as_u64(&self) -> Result<u64>137     pub fn as_u64(&self) -> Result<u64> {
138         match &self {
139             KeyID::V4(ref b) =>
140                 Ok(u64::from_be_bytes(*b)),
141             KeyID::Invalid(_) =>
142                 Err(Error::InvalidArgument("Invalid KeyID".into()).into()),
143             KeyID::__Nonexhaustive => unreachable!(),
144         }
145     }
146 
147     /// Reads a binary key ID.
from_bytes(raw: &[u8]) -> KeyID148     pub fn from_bytes(raw: &[u8]) -> KeyID {
149         if raw.len() == 8 {
150             let mut keyid : [u8; 8] = Default::default();
151             keyid.copy_from_slice(raw);
152             KeyID::V4(keyid)
153         } else {
154             KeyID::Invalid(raw.to_vec().into_boxed_slice())
155         }
156     }
157 
158     /// Returns a reference to the raw KeyID.
as_bytes(&self) -> &[u8]159     pub fn as_bytes(&self) -> &[u8] {
160         match self {
161             &KeyID::V4(ref id) => id,
162             &KeyID::Invalid(ref id) => id,
163             KeyID::__Nonexhaustive => unreachable!(),
164         }
165     }
166 
167     /// Returns the wildcard KeyID.
wildcard() -> Self168     pub fn wildcard() -> Self {
169         Self::from_bytes(&[0u8; 8][..])
170     }
171 
172     /// Returns true if this is a wild card ID.
is_wildcard(&self) -> bool173     pub fn is_wildcard(&self) -> bool {
174         self.as_bytes().iter().all(|b| *b == 0)
175     }
176 
177     /// Converts this key ID to its canonical hexadecimal representation.
178     ///
179     /// This representation is always uppercase and without spaces and is
180     /// suitable for stable key identifiers.
181     ///
182     /// The output of this function is exactly the same as formatting this
183     /// object with the `:X` format specifier.
184     ///
185     /// ```rust
186     /// # extern crate sequoia_openpgp as openpgp;
187     /// use openpgp::KeyID;
188     ///
189     /// let keyid = "fb3751f1587daef1".parse::<KeyID>().unwrap();
190     ///
191     /// assert_eq!("FB3751F1587DAEF1", keyid.to_hex());
192     /// assert_eq!(format!("{:X}", keyid), keyid.to_hex());
193     /// ```
to_hex(&self) -> String194     pub fn to_hex(&self) -> String {
195         format!("{:X}", self)
196     }
197 
198     /// Parses the hexadecimal representation of an OpenPGP key ID.
199     ///
200     /// This function is the reverse of `to_hex`. It also accepts other variants
201     /// of the key ID notation including lower-case letters, spaces and optional
202     /// leading `0x`.
203     ///
204     /// ```rust
205     /// # extern crate sequoia_openpgp as openpgp;
206     /// use openpgp::KeyID;
207     ///
208     /// let keyid = KeyID::from_hex("0xfb3751f1587daef1").unwrap();
209     ///
210     /// assert_eq!("FB3751F1587DAEF1", keyid.to_hex());
211     /// ```
from_hex(s: &str) -> std::result::Result<Self, anyhow::Error>212     pub fn from_hex(s: &str) -> std::result::Result<Self, anyhow::Error> {
213         std::str::FromStr::from_str(s)
214     }
215 
216     /// Common code for the above functions.
convert_to_string(&self, pretty: bool) -> String217     fn convert_to_string(&self, pretty: bool) -> String {
218         let raw = match self {
219             &KeyID::V4(ref fp) => &fp[..],
220             &KeyID::Invalid(ref fp) => &fp[..],
221             KeyID::__Nonexhaustive => unreachable!(),
222         };
223 
224         // We currently only handle V4 key IDs, which look like:
225         //
226         //   AACB 3243 6300 52D9
227         //
228         // Since we have no idea how to format an invalid key ID, just
229         // format it like a V4 fingerprint and hope for the best.
230 
231         let mut output = Vec::with_capacity(
232             // Each byte results in to hex characters.
233             raw.len() * 2
234             + if pretty {
235                 // Every 2 bytes of output, we insert a space.
236                 raw.len() / 2
237             } else { 0 });
238 
239         for (i, b) in raw.iter().enumerate() {
240             if pretty && i > 0 && i % 2 == 0 {
241                 output.push(' ' as u8);
242             }
243 
244             let top = b >> 4;
245             let bottom = b & 0xFu8;
246 
247             if top < 10u8 {
248                 output.push('0' as u8 + top)
249             } else {
250                 output.push('A' as u8 + (top - 10u8))
251             }
252 
253             if bottom < 10u8 {
254                 output.push('0' as u8 + bottom)
255             } else {
256                 output.push('A' as u8 + (bottom - 10u8))
257             }
258         }
259 
260         // We know the content is valid UTF-8.
261         String::from_utf8(output).unwrap()
262     }
263 }
264 
265 #[cfg(any(test, feature = "quickcheck"))]
266 impl Arbitrary for KeyID {
arbitrary<G: Gen>(g: &mut G) -> Self267     fn arbitrary<G: Gen>(g: &mut G) -> Self {
268         KeyID::new(u64::arbitrary(g))
269     }
270 }
271 
272 #[cfg(test)]
273 mod test {
274     use super::*;
275     quickcheck! {
276         fn u64_roundtrip(id: u64) -> bool {
277             KeyID::new(id).as_u64().unwrap() == id
278         }
279     }
280 
281     #[test]
from_hex()282     fn from_hex() {
283         "FB3751F1587DAEF1".parse::<KeyID>().unwrap();
284         "39D100AB67D5BD8C04010205FB3751F1587DAEF1".parse::<KeyID>()
285             .unwrap();
286         "0xFB3751F1587DAEF1".parse::<KeyID>().unwrap();
287         "0x39D100AB67D5BD8C04010205FB3751F1587DAEF1".parse::<KeyID>()
288             .unwrap();
289         "FB37 51F1 587D AEF1".parse::<KeyID>().unwrap();
290         "39D1 00AB 67D5 BD8C 0401  0205 FB37 51F1 587D AEF1".parse::<KeyID>()
291             .unwrap();
292         "GB3751F1587DAEF1".parse::<KeyID>().unwrap_err();
293         "EFB3751F1587DAEF1".parse::<KeyID>().unwrap_err();
294         "%FB3751F1587DAEF1".parse::<KeyID>().unwrap_err();
295         assert_match!(KeyID::Invalid(_) = "587DAEF1".parse().unwrap());
296         assert_match!(KeyID::Invalid(_) = "0x587DAEF1".parse().unwrap());
297     }
298 
299     #[test]
hex_formatting()300     fn hex_formatting() {
301         let keyid = "FB3751F1587DAEF1".parse::<KeyID>().unwrap();
302         assert_eq!(format!("{:X}", keyid), "FB3751F1587DAEF1");
303         assert_eq!(format!("{:x}", keyid), "fb3751f1587daef1");
304     }
305 
306     #[test]
keyid_is_send_and_sync()307     fn keyid_is_send_and_sync() {
308         fn f<T: Send + Sync>(_: T) {}
309         f("89AB CDEF 0123 4567".parse::<KeyID>().unwrap());
310     }
311 }
312