summaryrefslogtreecommitdiffstats
path: root/openpgp/src/cert/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'openpgp/src/cert/mod.rs')
-rw-r--r--openpgp/src/cert/mod.rs3115
1 files changed, 3115 insertions, 0 deletions
diff --git a/openpgp/src/cert/mod.rs b/openpgp/src/cert/mod.rs
new file mode 100644
index 00000000..7817063d
--- /dev/null
+++ b/openpgp/src/cert/mod.rs
@@ -0,0 +1,3115 @@
+//! OpenPGP Certificates.
+
+use std::io;
+use std::cmp;
+use std::cmp::Ordering;
+use std::path::Path;
+use std::slice;
+use std::mem;
+use std::fmt;
+use std::ops::{Deref, DerefMut};
+use std::time;
+
+use crate::{
+ conversions::Time,
+ crypto::{hash::Hash, Signer},
+ Error,
+ Result,
+ RevocationStatus,
+ SignatureType,
+ HashAlgorithm,
+ packet,
+ packet::Signature,
+ packet::signature,
+ packet::Key,
+ packet::key,
+ packet::UserID,
+ packet::UserAttribute,
+ packet::Unknown,
+ Packet,
+ PacketPile,
+ KeyID,
+ Fingerprint,
+};
+use crate::parse::{Parse, PacketParserResult, PacketParser};
+use crate::types::{
+ ReasonForRevocation,
+ RevocationType,
+};
+
+mod builder;
+mod bindings;
+mod keyiter;
+mod parser;
+mod revoke;
+
+pub use self::builder::{CertBuilder, CipherSuite};
+
+pub use keyiter::KeyIter;
+
+pub use parser::{
+ KeyringValidity,
+ KeyringValidator,
+ CertParser,
+ CertValidity,
+ CertValidator,
+};
+
+pub use revoke::{
+ SubkeyRevocationBuilder,
+ CertRevocationBuilder,
+ UserAttributeRevocationBuilder,
+ UserIDRevocationBuilder,
+};
+
+const TRACE : bool = false;
+
+// Helper functions.
+
+/// Compare the creation time of two signatures. Order them so that
+/// the more recent signature is first.
+fn canonical_signature_order(a: Option<time::SystemTime>, b: Option<time::SystemTime>)
+ -> Ordering {
+ // Note: None < Some, so the normal ordering is:
+ //
+ // None, Some(old), Some(new)
+ //
+ // Reversing the ordering puts the signatures without a creation
+ // time at the end, which is where they belong.
+ a.cmp(&b).reverse()
+}
+
+fn sig_cmp(a: &Signature, b: &Signature) -> Ordering {
+ match canonical_signature_order(a.signature_creation_time(),
+ b.signature_creation_time()) {
+ Ordering::Equal => a.mpis().cmp(b.mpis()),
+ r => r
+ }
+}
+
+/// A key (primary or subkey, public or private) and any associated
+/// signatures.
+pub type KeyBinding<KeyPart, KeyRole> = ComponentBinding<Key<KeyPart, KeyRole>>;
+
+impl<K: key::KeyParts, R: key::KeyRole> KeyBinding<K, R>
+{
+ /// Gets the key packet's `SecretKeyMaterial`.
+ ///
+ /// Note: The key module installs conversion functions on
+ /// KeyBinding. They need to access the key's secret.
+ pub(crate) fn secret(&self)
+ -> Option<&crate::packet::key::SecretKeyMaterial> {
+ self.key().secret()
+ }
+}
+
+/// A primary key and any associated signatures.
+pub type PrimaryKeyBinding<KeyPart> = KeyBinding<KeyPart, key::PrimaryRole>;
+
+/// A subkey and any associated signatures.
+pub type SubkeyBinding<KeyPart> = KeyBinding<KeyPart, key::SubordinateRole>;
+
+/// A key (primary or subkey, public or private) and any associated
+/// signatures.
+pub type GenericKeyBinding
+ = ComponentBinding<Key<key::UnspecifiedParts, key::UnspecifiedRole>>;
+
+/// A User ID and any associated signatures.
+pub type UserIDBinding = ComponentBinding<UserID>;
+
+/// A User Attribute and any associated signatures.
+pub type UserAttributeBinding = ComponentBinding<UserAttribute>;
+
+/// An unknown component and any associated signatures.
+///
+/// Note: all signatures are stored as certifications.
+pub type UnknownBinding = ComponentBinding<Unknown>;
+
+/// A Cert component binding.
+///
+/// A Cert component is a primary key, a subkey, a user id, or a user
+/// attribute. A binding is a Cert component and any related
+/// signatures.
+#[derive(Debug, Clone, PartialEq)]
+pub struct ComponentBinding<C> {
+ component: C,
+
+ // Self signatures.
+ self_signatures: Vec<Signature>,
+
+ // Third-party certifications. (In general, this will only be by
+ // designated revokers.)
+ certifications: Vec<Signature>,
+
+ // Self revocations.
+ self_revocations: Vec<Signature>,
+
+ // Third-party revocations (e.g., designated revokers).
+ other_revocations: Vec<Signature>,
+}
+
+impl<C> ComponentBinding<C> {
+ /// Returns a reference to the component.
+ pub fn component(&self) -> &C {
+ &self.component
+ }
+
+ /// Returns a mutable reference to the component.
+ fn component_mut(&mut self) -> &mut C {
+ &mut self.component
+ }
+
+ /// Returns the active binding signature at time `t`.
+ ///
+ /// An active binding signature is a non-revoked, self-signature
+ /// that is alive at time `t` (`creation time <= t`, `t <=
+ /// expiry`).
+ ///
+ /// This function returns None if there are no active binding
+ /// signatures at time `t`.
+ pub fn binding_signature<T>(&self, t: T) -> Option<&Signature>
+ where T: Into<Option<time::SystemTime>>
+ {
+ let t = t.into().unwrap_or_else(|| time::SystemTime::now().canonicalize());
+
+ // Recall: the signatures are sorted by their creation time in
+ // descending order, i.e., newest first.
+ //
+ // We want the newest signature that is older than t. So,
+ // search for `t`.
+
+ let i =
+ // Usually, the first signature is what we are looking for.
+ // Short circuit the binary search.
+ if Some(t) >= self.self_signatures.get(0)
+ .and_then(|s| s.signature_creation_time())
+ {
+ 0
+ } else {
+ match self.self_signatures.binary_search_by(
+ |s| canonical_signature_order(
+ s.signature_creation_time(), Some(t)))
+ {
+ // If there are multiple matches, then we need to search
+ // backwards to find the first one. Consider:
+ //
+ // t: 9 8 8 8 8 7
+ // i: 0 1 2 3 4 5
+ //
+ // If we are looking for t == 8, then binary_search could
+ // return index 1, 2, 3 or 4.
+ Ok(mut i) => {
+ // XXX: we use PartialOrd to compare Tms due to
+ // https://github.com/rust-lang-deprecated/time/issues/180
+ while i > 0
+ && self.self_signatures[i - 1].signature_creation_time()
+ .cmp(&Some(t)) == Ordering::Equal
+ {
+ i -= 1;
+ }
+ i
+ }
+
+ // There was no match. `i` is where a new element could
+ // be inserted while maintaining the sorted order.
+ // Consider:
+ //
+ // t: 9 8 6 5
+ // i: 0 1 2 3
+ //
+ // If we are looing for t == 7, then binary_search will
+ // return i == 2. That's exactly where we should start
+ // looking.
+ Err(i) => i,
+ }
+ };
+
+ self.self_signatures[i..].iter().filter(|s| {
+ s.signature_alive(t, time::Duration::new(0, 0))
+ }).nth(0)
+ }
+
+ /// The self-signatures.
+ ///
+ /// The signatures are validated, and they are reverse sorted by
+ /// their creation time (newest first).
+ pub fn self_signatures(&self) -> &[Signature] {
+ &self.self_signatures
+ }
+
+ /// Any third-party certifications.
+ ///
+ /// The signatures are *not* validated. They are reverse sorted by
+ /// their creation time (newest first).
+ pub fn certifications(&self) -> &[Signature] {
+ &self.certifications
+ }
+
+ /// Revocations issued by the key itself.
+ ///
+ /// The revocations are validated, and they are reverse sorted by
+ /// their creation time (newest first).
+ pub fn self_revocations(&self) -> &[Signature] {
+ &self.self_revocations
+ }
+
+ /// Revocations issued by other keys.
+ ///
+ /// The revocations are *not* validated. They are reverse sorted
+ /// by their creation time (newest first).
+ pub fn other_revocations(&self) -> &[Signature] {
+ &self.other_revocations
+ }
+
+ /// Returns the component's revocation status at time `t`.
+ ///
+ /// A component is considered to be revoked at time `t` if:
+ ///
+ /// - There is a live revocation at time `t` that is newer than
+ /// all live self signatures at time `t`.
+ ///
+ /// - `hard_revocations_are_final` is true, and there is a hard
+ /// revocation (even if it is not live at time `t`, and even
+ /// if there is a newer self-signature).
+ ///
+ /// selfsig must be the newest live self signature at time `t`.
+ fn _revoked<'a, T>(&'a self, hard_revocations_are_final: bool,
+ selfsig: Option<&Signature>, t: T)
+ -> RevocationStatus<'a>
+ where T: Into<Option<time::SystemTime>>
+ {
+ // Fallback time.
+ let time_zero = || time::UNIX_EPOCH;
+ let t = t.into()
+ .unwrap_or_else(|| time::SystemTime::now().canonicalize());
+ let selfsig_creation_time
+ = selfsig.and_then(|s| s.signature_creation_time())
+ .unwrap_or_else(time_zero);
+
+ tracer!(TRACE, "ComponentBinding::_revoked", 0);
+ t!("hard_revocations_are_final: {}, selfsig: {:?}, t: {:?}",
+ hard_revocations_are_final,
+ selfsig_creation_time,
+ t);
+ if let Some(selfsig) = selfsig {
+ assert!(selfsig.signature_alive(t, time::Duration::new(0, 0)));
+ }
+
+ macro_rules! check {
+ ($revs:expr) => ({
+ let revs = $revs.iter().filter_map(|rev| {
+ if hard_revocations_are_final
+ && rev.reason_for_revocation()
+ .map(|(r, _)| {
+ r.revocation_type() == RevocationType::Hard
+ })
+ // If there is no Reason for Revocation
+ // packet, assume that it is a hard
+ // revocation.
+ .unwrap_or(true)
+ {
+ t!(" got a hard revocation: {:?}, {:?}",
+ rev.signature_creation_time()
+ .unwrap_or_else(time_zero),
+ rev.reason_for_revocation()
+ .map(|r| (r.0, String::from_utf8_lossy(r.1))));
+ Some(rev)
+ } else if selfsig_creation_time
+ > rev.signature_creation_time()
+ .unwrap_or_else(time_zero)
+ {
+ t!(" ignoring out of date revocation ({:?})",
+ rev.signature_creation_time()
+ .unwrap_or_else(time_zero));
+ None
+ } else if !rev.signature_alive(t, time::Duration::new(0, 0)) {
+ t!(" ignoring revocation that is not alive ({:?} - {:?})",
+ rev.signature_creation_time()
+ .unwrap_or_else(time_zero),
+ rev.signature_expiration_time()
+ .unwrap_or_else(|| time::Duration::new(0, 0)));
+ None
+ } else {
+ t!(" got a revocation: {:?} ({:?})",
+ rev.signature_creation_time()
+ .unwrap_or_else(time_zero),
+ rev.reason_for_revocation()
+ .map(|r| (r.0, String::from_utf8_lossy(r.1))));
+ Some(rev)
+ }
+ }).collect::<Vec<&Signature>>();
+
+ if revs.len() == 0 {
+ None
+ } else {
+ Some(revs)
+ }
+ })
+ }
+
+ if let Some(revs) = check!(&self.self_revocations) {
+ RevocationStatus::Revoked(revs)
+ } else if let Some(revs) = check!(&self.other_revocations) {
+ RevocationStatus::CouldBe(revs)
+ } else {
+ RevocationStatus::NotAsFarAsWeKnow
+ }
+ }
+
+ // Converts the component into an iterator over the contained
+ // packets.
+ fn into_packets<'a>(self) -> impl Iterator<Item=Packet>
+ where Packet: From<C>
+ {
+ let p : Packet = self.component.into();
+ std::iter::once(p)
+ .chain(self.self_signatures.into_iter().map(|s| s.into()))
+ .chain(self.certifications.into_iter().map(|s| s.into()))
+ .chain(self.self_revocations.into_iter().map(|s| s.into()))
+ .chain(self.other_revocations.into_iter().map(|s| s.into()))
+ }
+
+ // Sorts and dedups the binding's signatures.
+ //
+ // This function assumes that the signatures have already been
+ // cryptographically checked.
+ //
+ // Note: this uses Signature::eq to compare signatures. That
+ // function ignores unhashed packets. If there are two signatures
+ // that only differ in their unhashed subpackets, they will be
+ // deduped. The unhashed areas are *not* merged; the one that is
+ // kept is undefined.
+ fn sort_and_dedup(&mut self)
+ {
+ self.self_signatures.sort_by(sig_cmp);
+ self.self_signatures.dedup();
+
+ // There is no need to sort the certifications, but we do
+ // want to remove dups and sorting is a prerequisite.
+ self.certifications.sort_by(sig_cmp);
+ self.certifications.dedup();
+
+ self.self_revocations.sort_by(sig_cmp);
+ self.self_revocations.dedup();
+
+ self.other_revocations.sort_by(sig_cmp);
+ self.other_revocations.dedup();
+ }
+}
+
+impl<P: key::KeyParts, R: key::KeyRole> ComponentBinding<Key<P, R>> {
+ /// Returns a reference to the key.
+ pub fn key(&self) -> &Key<P, R> {
+ self.component()
+ }
+
+ /// Returns a mut reference to the key.
+ fn key_mut(&mut self) -> &mut Key<P, R> {
+ self.component_mut()
+ }
+}
+
+impl<P: key::KeyParts> ComponentBinding<Key<P, key::SubordinateRole>> {
+ /// Returns the subkey's revocation status at time `t`.
+ ///
+ /// A subkey is revoked at time `t` if:
+ ///
+ /// - There is a live revocation at time `t` that is newer than
+ /// all live self signatures at time `t`, or
+ ///
+ /// - There is a hard revocation (even if it is not live at
+ /// time `t`, and even if there is a newer self-signature).
+ ///
+ /// Note: Certs and subkeys have different criteria from User IDs
+ /// and User Attributes.
+ ///
+ /// Note: this only returns whether this subkey is revoked; it
+ /// does not imply anything about the Cert or other components.
+ pub fn revoked<T>(&self, t: T)
+ -> RevocationStatus
+ where T: Into<Option<time::SystemTime>>
+ {
+ let t = t.into();
+ self._revoked(true, self.binding_signature(t), t)
+ }
+}
+
+impl ComponentBinding<UserID> {
+ /// Returns a reference to the User ID.
+ pub fn userid(&self) -> &UserID {
+ self.component()
+ }
+
+ /// Returns the User ID's revocation status at time `t`.
+ ///
+ /// A User ID is revoked at time `t` if:
+ ///
+ /// - There is a live revocation at time `t` that is newer than
+ /// all live self signatures at time `t`, or
+ ///
+ /// Note: Certs and subkeys have different criteria from User IDs
+ /// and User Attributes.
+ ///
+ /// Note: this only returns whether this User ID is revoked; it
+ /// does not imply anything about the Cert or other components.
+ pub fn revoked<T>(&self, t: T)
+ -> RevocationStatus
+ where T: Into<Option<time::SystemTime>>
+ {
+ let t = t.into();
+ self._revoked(false, self.binding_signature(t), t)
+ }
+}
+
+impl ComponentBinding<UserAttribute> {
+ /// Returns a reference to the User Attribute.
+ pub fn user_attribute(&self) -> &UserAttribute {
+ self.component()
+ }
+
+ /// Returns the User Attribute's revocation status at time `t`.
+ ///
+ /// A User Attribute is revoked at time `t` if:
+ ///
+ /// - There is a live revocation at time `t` that is newer than
+ /// all live self signatures at time `t`, or
+ ///
+ /// Note: Certs and subkeys have different criteria from User IDs
+ /// and User Attributes.
+ ///
+ /// Note: this only returns whether this User Attribute is revoked;
+ /// it does not imply anything about the Cert or other components.
+ pub fn revoked<T>(&self, t: T)
+ -> RevocationStatus
+ where T: Into<Option<time::SystemTime>>
+ {
+ let t = t.into();
+ self._revoked(false, self.binding_signature(t), t)
+ }
+}
+
+impl ComponentBinding<Unknown> {
+ /// Returns a reference to the unknown component.
+ pub fn unknown(&self) -> &Unknown {
+ self.component()
+ }
+}
+
+
+impl fmt::Display for Cert {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.primary().fingerprint())
+ }
+}
+
+/// An iterator over `ComponentBinding`s.
+pub struct ComponentBindingIter<'a, C> {
+ iter: Option<slice::Iter<'a, ComponentBinding<C>>>,
+}
+
+/// An iterator over `KeyBinding`s.
+pub type KeyBindingIter<'a, P, R> = ComponentBindingIter<'a, Key<P, R>>;
+/// An iterator over `UserIDBinding`s.
+pub type UserIDBindingIter<'a> = ComponentBindingIter<'a, UserID>;
+/// An iterator over `UserAttributeBinding`s.
+pub type UserAttributeBindingIter<'a> = ComponentBindingIter<'a, UserAttribute>;
+/// An iterator over `UnknownBinding`s.
+pub type UnknownBindingIter<'a> = ComponentBindingIter<'a, Unknown>;
+
+impl<'a, C> Iterator for ComponentBindingIter<'a, C>
+{
+ type Item = &'a ComponentBinding<C>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match self.iter {
+ Some(ref mut iter) => iter.next(),
+ None => None,
+ }
+ }
+}
+
+impl<'a, C> ExactSizeIterator for ComponentBindingIter<'a, C>
+{
+ fn len(&self) -> usize {
+ match self.iter {
+ Some(ref iter) => iter.len(),
+ None => 0,
+ }
+ }
+}
+
+/// A collection of `ComponentBindings`.
+///
+/// Note: we need this, because we can't `impl Vec<ComponentBindings>`.
+#[derive(Debug, Clone, PartialEq)]
+pub struct ComponentBindings<C>
+ where ComponentBinding<C>: cmp::PartialEq
+{
+ bindings: Vec<ComponentBinding<C>>,
+}
+
+impl<C> Deref for ComponentBindings<C>
+ where ComponentBinding<C>: cmp::PartialEq
+{
+ type Target = Vec<ComponentBinding<C>>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.bindings
+ }
+}
+
+impl<C> DerefMut for ComponentBindings<C>
+ where ComponentBinding<C>: cmp::PartialEq
+{
+ fn deref_mut(&mut self) -> &mut Vec<ComponentBinding<C>> {
+ &mut self.bindings
+ }
+}
+
+impl<C> Into<Vec<ComponentBinding<C>>> for ComponentBindings<C>
+ where ComponentBinding<C>: cmp::PartialEq
+{
+ fn into(self) -> Vec<ComponentBinding<C>> {
+ self.bindings
+ }
+}
+
+impl<C> IntoIterator for ComponentBindings<C>
+ where ComponentBinding<C>: cmp::PartialEq
+{
+ type Item = ComponentBinding<C>;
+ type IntoIter = std::vec::IntoIter<Self::Item>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.bindings.into_iter()
+ }
+}
+
+impl<C> ComponentBindings<C>
+ where ComponentBinding<C>: cmp::PartialEq
+{
+ fn new() -> Self {
+ Self { bindings: vec![] }
+ }
+}
+
+impl<C> ComponentBindings<C>
+ where ComponentBinding<C>: cmp::PartialEq
+{
+ // Sort and dedup the components.
+ //
+ // `cmp` is a function to sort the components for deduping.
+ //
+ // `merge` is a function that merges the first component into the
+ // second component.
+ fn sort_and_dedup<F, F2>(&mut self, cmp: F, merge: F2)
+ where F: Fn(&C, &C) -> Ordering,
+ F2: Fn(&mut C, &mut C)
+ {
+ // We dedup by component (not bindings!). To do this, we need
+ // to sort the bindings by their components.
+
+ self.bindings.sort_unstable_by(
+ |a, b| cmp(&a.component, &b.component));
+
+ self.bindings.dedup_by(|a, b| {
+ if cmp(&a.component, &b.component) == Ordering::Equal {
+ // Merge.
+ merge(&mut a.component, &mut b.component);
+
+ // Recall: if a and b are equal, a will be dropped.
+ b.self_signatures.append(&mut a.self_signatures);
+ b.certifications.append(&mut a.certifications);
+ b.self_revocations.append(&mut a.self_revocations);
+ b.other_revocations.append(&mut a.self_revocations);
+
+ true
+ } else {
+ false
+ }
+ });
+
+ // And sort the certificates.
+ for b in self.bindings.iter_mut() {
+ b.sort_and_dedup();
+ }
+ }
+}
+
+/// A vecor of key (primary or subkey, public or private) and any
+/// associated signatures.
+pub type KeyBindings<KeyPart, KeyRole> = ComponentBindings<Key<KeyPart, KeyRole>>;
+
+/// A vector of subkeys and any associated signatures.
+pub type SubkeyBindings<KeyPart> = KeyBindings<KeyPart, key::SubordinateRole>;
+
+/// A vector of key (primary or subkey, public or private) and any
+/// associated signatures.
+pub type GenericKeyBindings
+ = ComponentBindings<Key<key::UnspecifiedParts, key::UnspecifiedRole>>;
+
+/// A vector of User ID bindings and any associated signatures.
+pub type UserIDBindings = ComponentBindings<UserID>;
+
+/// A vector of User Attribute bindings and any associated signatures.
+pub type UserAttributeBindings = ComponentBindings<UserAttribute>;
+
+/// A vector of unknown components and any associated signatures.
+///
+/// Note: all signatures are stored as certifications.
+pub type UnknownBindings = ComponentBindings<Unknown>;
+
+
+/// A OpenPGP Certificate.
+///
+/// A Certificate (see [RFC 4880, section 11.1]) can be used to verify
+/// signatures and encrypt data. It can be stored in a keystore and
+/// uploaded to keyservers.
+///
+/// Certs are always canonicalized in the sense that only elements
+/// (user id, user attribute, subkey) with at least one valid
+/// self-signature are preserved. Also, invalid self-signatures are
+/// dropped. The self-signatures are sorted so that the newest
+/// self-signature comes first. Components are sorted, but in an
+/// undefined manner (i.e., when parsing the same Cert multiple times,
+/// the components will be in the same order, but we reserve the right
+/// to change the sort function between versions). Third-party
+/// certifications are *not* validated, as the keys are not available;
+/// they are simply passed through as is.
+///
+/// [RFC 4880, section 11.1]: https://tools.ietf.org/html/rfc4880#section-11.1
+///
+/// # Secret keys
+///
+/// Any key in a `Cert` may have a secret key attached to it. To
+/// protect secret keys from being leaked, secret keys are not written
+/// out if a `Cert` is serialized. To also serialize the secret keys,
+/// you need to use [`Cert::as_tsk()`] to get an object that writes
+/// them out during serialization.
+///
+/// [`Cert::as_tsk()`]: #method.as_tsk
+///
+/// # Example
+///
+/// ```rust
+/// # extern crate sequoia_openpgp as openpgp;
+/// # use openpgp::Result;
+/// # use openpgp::parse::{Parse, PacketParserResult, PacketParser};
+/// use openpgp::Cert;
+///
+/// # fn main() { f().unwrap(); }
+/// # fn f() -> Result<()> {
+/// # let ppr = PacketParser::from_bytes(&b""[..])?;
+/// match Cert::from_packet_parser(ppr) {
+/// Ok(cert) => {
+/// println!("Key: {}", cert.primary());
+/// for binding in cert.userids() {
+/// println!("User ID: {}", binding.userid());
+/// }
+/// }
+/// Err(err) => {
+/// eprintln!("Error parsing Cert: {}", err);
+/// }
+/// }
+///
+/// # Ok(())
+/// # }
+#[derive(Debug, Clone, PartialEq)]
+pub struct Cert {
+ primary: PrimaryKeyBinding<key::PublicParts>,
+
+ userids: UserIDBindings,
+ user_attributes: UserAttributeBindings,
+ subkeys: SubkeyBindings<key::PublicParts>,
+
+ // Unknown components, e.g., some UserAttribute++ packet from the
+ // future.
+ unknowns: UnknownBindings,
+ // Signatures that we couldn't find a place for.
+ bad: Vec<packet::Signature>,
+}
+
+impl std::str::FromStr for Cert {
+ type Err = failure::Error;
+
+ fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+ Self::from_bytes(s.as_bytes())
+ }
+}
+
+impl<'a> Parse<'a, Cert> for Cert {
+ /// Returns the first Cert encountered in the reader.
+ fn from_reader<R: io::Read>(reader: R) -> Result<Self> {
+ Cert::from_packet_parser(PacketParser::from_reader(reader)?)
+ }
+
+ /// Returns the first Cert encountered in the file.
+ fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
+ Cert::from_packet_parser(PacketParser::from_file(path)?)
+ }
+
+ /// Returns the first Cert found in `buf`.
+ ///
+ /// `buf` must be an OpenPGP-encoded message.
+ fn from_bytes<D: AsRef<[u8]> + ?Sized>(data: &'a D) -> Result<Self> {
+ Cert::from_packet_parser(PacketParser::from_bytes(data)?)
+ }
+}
+
+impl Cert {
+ /// Returns a reference to the primary key binding.
+ ///
+ /// Note: information about the primary key is often stored on the
+ /// primary User ID's self signature. Since these signatures are
+ /// associated with the UserID and not the primary key, that
+ /// information is not contained in the key binding. Instead, you
+ /// should use methods like `Cert::primary_key_signature()` to get
+ /// information about the primary key.
+ pub fn primary(&self) -> &key::PublicKey {
+ &self.primary.key()
+ }
+
+ /// Returns the binding for the primary User ID at time `t`.
+ ///
+ /// See `Cert::primary_userid_full` for a description of how the
+ /// primary user id is determined.
+ pub fn primary_userid<T>(&self, t: T) -> Option<&UserIDBinding>
+ where T: Into<Option<time::SystemTime>>
+ {
+ self.primary_userid_full(t).map(|r| r.0)
+ }
+
+ /// Returns the binding for the primary User ID at time `t` and
+ /// some associated data.
+ ///
+ /// In addition to the User ID binding, this also returns the
+ /// binding signature and the User ID's `RevocationStatus` at time
+ /// `t`.
+ ///
+ /// The primary User ID is determined by taking the User IDs that
+ /// are alive at time `t`, and sorting them as follows:
+ ///
+ /// - non-revoked first
+ /// - primary first
+ /// - signature creation first
+ ///
+ /// If there is more than one, than one is selected in a
+ /// deterministic, but undefined manner.
+ pub fn primary_userid_full<T>(&self, t: T)
+ -> Option<(&UserIDBinding, &Signature, RevocationStatus)>
+ where T: Into<Option<time::SystemTime>>
+ {
+ let t = t.into()
+ .unwrap_or_else(|| time::SystemTime::now().canonicalize());
+ self.userids()
+ // Filter out User IDs that are not alive at time `t`.
+ //
+ // While we have the binding signature, extract a few
+ // properties to avoid recomputing the same thing multiple
+ // times.
+ .filter_map(|b| {
+ // No binding signature at time `t` => not alive.
+ let selfsig = b.binding_signature(t)?;
+
+ if !selfsig.signature_alive(t, time::Duration::new(0, 0)) {
+ return None;
+ }
+
+ let revoked = b.revoked(t);
+ let primary = selfsig.primary_userid().unwrap_or(false);