diff options
Diffstat (limited to 'openpgp/src/tpk/mod.rs')
-rw-r--r-- | openpgp/src/tpk/mod.rs | 417 |
1 files changed, 324 insertions, 93 deletions
diff --git a/openpgp/src/tpk/mod.rs b/openpgp/src/tpk/mod.rs index eca1448b..394f9922 100644 --- a/openpgp/src/tpk/mod.rs +++ b/openpgp/src/tpk/mod.rs @@ -20,6 +20,7 @@ use { packet::Tag, packet::signature::{self, Signature}, packet::Key, + packet::key::SecretKey, packet::UserID, packet::UserAttribute, packet::Unknown, @@ -861,32 +862,312 @@ pub struct UnknownBinding { /// in a TPK. /// /// Returned by TPK::keys(). +/// +/// `KeyIter` follows the builder pattern. There is no need to +/// explicitly finalize it, however: it already implements the +/// `Iterator` interface. +/// +/// By default, `KeyIter` will only return live, non-revoked keys. It +/// is possible to control how `KeyIter` filters using, for instance, +/// `KeyIter::flags` to only return keys with particular flags set. pub struct KeyIter<'a> { - tpk: &'a TPK, + // This is an option to make it easier to create an empty KeyIter. + tpk: Option<&'a TPK>, primary: bool, subkey_iter: SubkeyBindingIter<'a>, + + // If not None, only returns keys with the specified flags. + flags: Option<KeyFlags>, + + // If not None, only returns keys that are live at the specified + // time. + alive_at: Option<time::Tm>, + + // If not None, filters by revocation status. + revoked: Option<bool>, + + // If not None, filters by whether a key has a secret. + secret: Option<bool>, + + // If not None, filters by whether a key has an unencrypted + // secret. + unencrypted_secret: Option<bool>, +} + +impl<'a> fmt::Debug for KeyIter<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("KeyIter") + .field("flags", &self.flags) + .field("alive_at", &self.alive_at) + .field("revoked", &self.revoked) + .field("secret", &self.secret) + .field("unencrypted_secret", &self.unencrypted_secret) + .finish() + } } impl<'a> Iterator for KeyIter<'a> { type Item = (Option<&'a Signature>, RevocationStatus<'a>, &'a Key); fn next(&mut self) -> Option<Self::Item> { - if ! self.primary { - self.primary = true; - Some((self.tpk.primary_key_signature(), - self.tpk.revoked(None), - self.tpk.primary())) - } else { - self.subkey_iter.next() - .map(|sk_binding| (sk_binding.binding_signature(), - sk_binding.revoked(None), - &sk_binding.subkey,)) + tracer!(false, "KeyIter::next", 0); + t!("KeyIter: {:?}", self); + + if self.tpk.is_none() { + return None; + } + let tpk = self.tpk.unwrap(); + + if let Some(flags) = self.flags.as_ref() { + if flags.is_empty() { + // Nothing to do. + t!("short circuiting: flags is empty"); + return None; + } + } + + loop { + let (sigo, revoked, key) = if ! self.primary { + self.primary = true; + + (tpk.primary_key_signature(), + tpk.revoked(None), + tpk.primary()) + } else { + self.subkey_iter.next() + .map(|sk_binding| (sk_binding.binding_signature(), + sk_binding.revoked(None), + &sk_binding.subkey,))? + }; + + t!("Considering key: {:?}", key); + + if let Some(flags) = self.flags.as_ref() { + if let Some(sig) = sigo { + if (&sig.key_flags() & &flags).is_empty() { + t!("Have flags: {:?}, want flags: {:?}... skipping.", + sig.key_flags(), flags); + continue; + } + } else { + // No self-signature, skip it. + t!("No self-signature... skipping."); + continue; + } + } + + if let Some(alive_at) = self.alive_at { + if let Some(sig) = sigo { + if ! sig.key_alive_at(key, alive_at) { + t!("Key not alive... skipping."); + continue; + } + } else { + // No self-signature, skip it. + t!("No self-signature... skipping."); + continue; + } + } + + if let Some(want_revoked) = self.revoked { + if let RevocationStatus::Revoked(_) = revoked { + // The key is definitely revoked. + if ! want_revoked { + t!("Key revoked... skipping."); + continue; + } + } else { + // The key is probably not revoked. + if want_revoked { + t!("Key not revoked... skipping."); + continue; + } + } + } + + if let Some(want_secret) = self.secret { + if key.secret().is_some() { + // We have a secret. + if ! want_secret { + t!("Have a secret... skipping."); + continue; + } + } else { + if want_secret { + t!("No secret... skipping."); + continue; + } + } + } + + if let Some(want_unencrypted_secret) = self.unencrypted_secret { + if let Some(secret) = key.secret() { + if let SecretKey::Unencrypted { .. } = secret { + if ! want_unencrypted_secret { + t!("Unencrypted secret... skipping."); + continue; + } + } else { + if want_unencrypted_secret { + t!("Encrypted secret... skipping."); + continue; + } + } + } else { + // No secret. + t!("No secret... skipping."); + continue; + } + } + + return Some((sigo, revoked, key)); } } } -impl<'a> ExactSizeIterator for KeyIter<'a> { - fn len(&self) -> usize { 1 + self.subkey_iter.len() } +impl<'a> KeyIter<'a> { + /// Returns a new `KeyIter` instance with no filters enabled. + fn new(tpk: &'a TPK) -> Self where Self: 'a { + KeyIter { + tpk: Some(tpk), + primary: false, + subkey_iter: tpk.subkeys(), + + // The filters. + flags: None, + alive_at: None, + revoked: None, + secret: None, + unencrypted_secret: None, + } + } + + /// Clears all filters. + /// + /// This causes the `KeyIter` to return all keys in the TPK. + pub fn unfiltered(self) -> Self { + KeyIter::new(self.tpk.unwrap()) + } + + /// Returns an empty KeyIter. + pub fn empty() -> Self { + KeyIter { + tpk: None, + primary: false, + subkey_iter: SubkeyBindingIter { iter: None }, + + // The filters. + flags: None, + alive_at: None, + revoked: None, + secret: None, + unencrypted_secret: None, + } + } + + /// Returns keys that have the at least one of the flags specified + /// in `flags`. + /// + /// If you call this function (or one of `certification_capable` + /// or `signing_capable` functions) multiple times, the *union* of + /// the values is used. Thus, + /// `tpk.flags().certification_capable().signing_capable()` will + /// return keys that are certification capable or signing capable. + /// + /// If you need more complex filtering, e.g., you want a key that + /// is both certification and signing capable, then just use a + /// normal [`Iterator::filter`]. + /// + /// [`Iterator::filter`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter + pub fn key_flags(mut self, flags: KeyFlags) -> Self { + if let Some(flags_old) = self.flags { + self.flags = Some(&flags | &flags_old); + } else { + self.flags = Some(flags); + } + self + } + + /// Returns keys that are certification capable. + /// + /// See `key_flags` for caveats. + pub fn certification_capable(self) -> Self { + self.key_flags(KeyFlags::default().set_certify(true)) + } + + /// Returns keys that are signing capable. + /// + /// See `key_flags` for caveats. + pub fn signing_capable(self) -> Self { + self.key_flags(KeyFlags::default().set_sign(true)) + } + + /// Only returns keys that are live as of `now`. + /// + /// If `now` is none, then all keys are returned whether they are + /// live or not. + /// + /// A value of None disables this filter, which is set by default + /// to only return live keys at the current time. + /// + /// If you call this function (or `alive`) multiple times, only + /// the last value is used. + pub fn alive_at<T>(mut self, alive_at: T) -> Self + where T: Into<Option<time::Tm>> + { + self.alive_at = alive_at.into(); + self + } + + /// Only returns keys that are live right now. + /// + /// If you call this function (or `alive_at`) multiple times, only + /// the last value is used. + pub fn alive(mut self) -> Self + { + self.alive_at = Some(time::now()); + self + } + + /// If not None, filters by whether a key is definitely revoked. + /// + /// That is, whether it's revocation status is + /// `RevocationStatus::Revoked`. + /// + /// A value of None disables this filter, which is set by default + /// to not return revoked keys. + /// + /// If you call this function multiple times, only the last value + /// is used. + pub fn revoked<T>(mut self, revoked: T) -> Self + where T: Into<Option<bool>> + { + self.revoked = revoked.into(); + self + } + + /// If not None, filters by whether a key has a secret. + /// + /// If you call this function multiple times, only the last value + /// is used. + pub fn secret<T>(mut self, secret: T) -> Self + where T: Into<Option<bool>> + { + self.secret = secret.into(); + self + } + + /// If not None, filters by whether a key has an unencrypted + /// secret. + /// + /// If you call this function multiple times, only the last value + /// is used. + pub fn unencrypted_secret<T>(mut self, unencrypted_secret: T) -> Self + where T: Into<Option<bool>> + { + self.unencrypted_secret = unencrypted_secret.into(); + self + } } // A TPKParser can read packets from either an Iterator or a @@ -1343,19 +1624,27 @@ impl<'a> ExactSizeIterator for UserAttributeBindingIter<'a> { /// An iterator over `SubkeyBinding`s. pub struct SubkeyBindingIter<'a> { - iter: slice::Iter<'a, SubkeyBinding>, + iter: Option<slice::Iter<'a, SubkeyBinding>>, } impl<'a> Iterator for SubkeyBindingIter<'a> { type Item = &'a SubkeyBinding; fn next(&mut self) -> Option<Self::Item> { - self.iter.next() + match self.iter { + Some(ref mut iter) => iter.next(), + None => None, + } } } impl<'a> ExactSizeIterator for SubkeyBindingIter<'a> { - fn len(&self) -> usize { self.iter.len() } + fn len(&self) -> usize { + match self.iter { + Some(ref iter) => iter.len(), + None => 0, + } + } } @@ -1695,10 +1984,11 @@ impl TPK { /// /// A valid `SubkeyBinding` has at least one good self-signature. pub fn subkeys(&self) -> SubkeyBindingIter { - SubkeyBindingIter { iter: self.subkeys.iter() } + SubkeyBindingIter { iter: Some(self.subkeys.iter()) } } - /// Returns an iterator over all of the TPK's valid keys. + /// Returns an iterator over the TPK's valid keys (live and + /// not-revoked). /// /// That is, this returns an iterator over the primary key and any /// subkeys, along with the corresponding signatures. @@ -1712,79 +2002,20 @@ impl TPK { /// `None` for the primary key's signature. /// /// A valid `Key` has at least one good self-signature. - pub fn keys(&self) -> KeyIter { - KeyIter { - tpk: self, - primary: false, - subkey_iter: self.subkeys() - } - } - - /// Returns all unrevoked (sub)keys that have all capabilities in `cap` and - /// are valid `now`. If `now` is `None` the current time is used. /// - /// Keys are sorted by creation time (newest first). If the primary key - /// qualifies it will always be last. Using the first key should suffice - /// for most use cases. - pub fn select_keys<'a, T>(&'a self, cap: KeyFlags, now: T) - -> Vec<&'a Key> - where T: Into<Option<time::Tm>> { - use std::slice; - use std::iter; - use std::borrow::Borrow; - - fn is_usable<S>(key: &Key, mut bindings: slice::Iter<S>, now: time::Tm, - cap: &KeyFlags) -> bool where S: Borrow<Signature> { - let key_now_valid = *key.creation_time() < now; - let sig_now_valid = bindings.clone().any(|sig| { - sig.borrow().signature_alive_at(now) - }); - let right_caps = bindings.any(|sig| { - *cap <= sig.borrow().key_flags() - }); - - key_now_valid && sig_now_valid && right_caps - } - let now = now.into().unwrap_or_else(time::now); - - if self.revoked(now) == RevocationStatus::NotAsFarAsWeKnow { - let prim_sigs = match self.primary_key_signature_full() { - None => Vec::default(), - Some((None, sig)) => vec![sig], - Some((Some(uid), sig)) => - uid.selfsigs().iter().chain(iter::once(sig)).collect(), - }; - let prim = Some(&self.primary) - .filter(|k| is_usable(k, prim_sigs.iter(), now, &cap)); - let mut ret = self.subkeys - .iter() - .filter(|sb| { - sb.revoked(None) == RevocationStatus::NotAsFarAsWeKnow && - is_usable(sb.subkey(), sb.selfsigs().iter(), now, &cap) - }) - .map(|sb| sb.subkey()) - .collect::<Vec<_>>(); - - ret.sort_by(|a,b| b.creation_time().cmp(a.creation_time())); - ret.extend(prim); - - ret - } else { - Vec::default() - } + /// To return all keys, do `keys().unfiltered()`. See the + /// documentation of `keys` for how to control what keys are + /// returned. + pub fn keys_valid(&self) -> KeyIter { + KeyIter::new(self).alive().revoked(false) } - /// Returns all unrevoked (sub)keys that have the signing - /// capability and are valid `now`. If `now` is `None` the current - /// time is used. + /// Returns an iterator over the TPK's keys. /// - /// Keys are sorted by creation time (newest first). If the - /// primary key qualifies it will always be last. Using the first - /// key should suffice for most use cases. - pub fn select_signing_keys<'a, T>(&'a self, now: T) -> Vec<&'a Key> - where T: Into<Option<time::Tm>> - { - self.select_keys(KeyFlags::default().set_sign(true), now) + /// Unlike `TPK::keys_valid()`, this iterator also returns expired + /// and revoked keys. + pub fn keys_all(&self) -> KeyIter { + KeyIter::new(self) } /// Returns the first TPK found in the packet stream. @@ -3111,7 +3342,7 @@ mod test { fn key_iter_test() { let key = TPK::from_bytes(bytes!("neal.pgp")).unwrap(); assert_eq!(1 + key.subkeys().count(), - key.keys().count()); + key.keys_all().count()); } #[test] @@ -3702,7 +3933,7 @@ mod test { .generate().unwrap(); let flags = KeyFlags::default().set_encrypt_for_transport(true); - assert!(tpk.select_keys(flags, None).is_empty()); + assert_eq!(tpk.keys_all().key_flags(flags).count(), 0); } #[test] @@ -3712,7 +3943,7 @@ mod test { .generate().unwrap(); let flags = KeyFlags::default().set_encrypt_for_transport(true); - assert_eq!(tpk.select_keys(flags, None).len(), 1); + assert_eq!(tpk.keys_all().key_flags(flags).count(), 1); } #[test] @@ -3723,7 +3954,7 @@ mod test { .generate().unwrap(); let flags = KeyFlags::default().set_encrypt_for_transport(true); - assert_eq!(tpk.select_keys(flags, None).len(), 1); + assert_eq!(tpk.keys_all().key_flags(flags).count(), 1); } #[test] @@ -3735,7 +3966,7 @@ mod test { let flags = KeyFlags::default().set_encrypt_for_transport(true); now.tm_year -= 1; - assert_eq!(tpk.select_keys(flags, now).len(), 0); + assert_eq!(tpk.keys_all().key_flags(flags).alive_at(now).count(), 0); } #[test] @@ -3745,7 +3976,7 @@ mod test { .generate().unwrap(); let flags = KeyFlags::default().set_certify(true); - assert_eq!(tpk.select_keys(flags, None).len(), 2); + assert_eq!(tpk.keys_all().key_flags(flags).count(), 2); } // Make sure that when merging two TPKs, the primary key and |