sequoia-openpgp 1.13.0

OpenPGP data types and associated machinery
Documentation
//! A certificate component and its associated signatures.
//!
//! Certificates ([`Cert`]s) are a collection of components where each
//! component corresponds to a [`Packet`], and each component has zero
//! or more associated [`Signature`]s.  A [`ComponentBundle`]
//! encapsulates a component and its associated signatures.
//!
//! Sequoia supports four different kinds of components: [`Key`]s,
//! [`UserID`]s, [`UserAttribute`]s, and [`Unknown`] components.  The
//! `Unknown` component has two purposes.  First, it is used to store
//! packets that appear in a certificate and have an unknown [`Tag`].
//! By not silently dropping these packets, it is possible to round
//! trip certificates without losing any information.  This provides a
//! measure of future compatibility.  Second, the `Unknown` component
//! is used to store unsupported components.  For instance, Sequoia
//! doesn't support v3 `Key`s, which are deprecated, or v5 `Key`s,
//! which are still being standardized.  Because these keys are
//! effectively unusable, they are stored as `Unknown` components
//! instead of `Key`s.
//!
//! There are four types of signatures associated with a component:
//! self signatures, self revocations, third-party signatures, and
//! third-party revocations.  When parsing a certificate, self
//! signatures and self revocations are checked for validity and
//! invalid signatures and revocations are discarded.  Since the keys
//! are not normally available, third-party signatures and third-party
//! revocations cannot be rigorously (i.e., cryptographically) checked
//! for validity.
//!
//! With the exception of the primary key, a component's self
//! signatures are binding signatures.  A binding signature firstly
//! binds the component to the certificate.  That is, it provides
//! cryptographic evidence that the certificate holder intended for
//! the component to be associated with the certificate.  Binding
//! signatures also provide information about the component.  For
//! instance, the binding signature for a subkey includes its
//! capabilities, and its expiry time.
//!
//! Since the primary key is the embodiment of the certificate, there
//! is nothing to bind it to.  Correspondingly, self signatures on a
//! primary key are called direct key signatures.  Direct key
//! signatures are used to provide information about the whole
//! certificate.  For instance, they can include the default `Key`
//! expiry time.  This is used if a subkey's binding signature doesn't
//! include a expiry.
//!
//! Self-revocations are revocation certificates issued by the key
//! certificate holder.
//!
//! Third-party signatures are typically signatures certifying that a
//! `User ID` or `User Attribute` accurately describes the certificate
//! holder.  This information is used by trust models, like the Web of
//! Trust, to indirectly authenticate keys.
//!
//! Third-party revocations are revocations issued by another
//! certificate.  They should normally only be respected if the
//! certificate holder made the issuer a so-called [designated
//! revoker].
//!
//! # Important
//!
//! When looking up information about a component, it is generally
//! better to use the [`ComponentAmalgamation`] or [`KeyAmalgamation`]
//! data structures.  These data structures provide convenience
//! methods that implement the [complicated semantics] for correctly
//! locating information.
//!
//! [`Cert`]: super
//! [`Packet`]: crate::packet
//! [`Signature`]: crate::packet::signature
//! [`Key`]: crate::packet::key
//! [`UserID`]: crate::packet::UserID
//! [`UserAttribute`]: crate::packet::user_attribute
//! [`Unknown`]: crate::packet::Unknown
//! [`Tag`]: crate::packet::Tag
//! [designated revoker]: https://tools.ietf.org/html/rfc4880#section-5.2.3.15
//! [`ComponentAmalgamation`]: super::amalgamation
//! [`KeyAmalgamation`]: super::amalgamation::key::KeyAmalgamation
//! [complicated semantics]: https://tools.ietf.org/html/rfc4880#section-5.2.3.3

use std::time;
use std::ops::Deref;

use crate::{
    Error,
    packet::Signature,
    packet::Key,
    packet::key,
    packet::UserID,
    packet::UserAttribute,
    packet::Unknown,
    Packet,
    policy::HashAlgoSecurity,
    policy::Policy,
    Result,
};
use crate::types::{
    RevocationType,
    RevocationStatus,
};

use super::{
    sig_cmp,
    canonical_signature_order,
};

/// A certificate component and its associated signatures.
///
/// [See the module level documentation](self) for a detailed
/// description.
#[derive(Debug, Clone, PartialEq)]
pub struct ComponentBundle<C> {
    pub(crate) component: C,

    pub(crate) hash_algo_security: HashAlgoSecurity,

    // Self signatures.
    pub(crate) self_signatures: Vec<Signature>,

    // Third-party certifications.  (In general, this will only be by
    // designated revokers.)
    pub(crate) certifications: Vec<Signature>,

    // Attestation key signatures.
    pub(crate) attestations: Vec<Signature>,

    // Self revocations.
    pub(crate) self_revocations: Vec<Signature>,

    // Third-party revocations (e.g., designated revokers).
    pub(crate) other_revocations: Vec<Signature>,
}
assert_send_and_sync!(ComponentBundle<C> where C);

/// A key (primary or subkey, public or private) and any associated
/// signatures.
///
/// [See the module level documentation.](self)
pub type KeyBundle<KeyPart, KeyRole> = ComponentBundle<Key<KeyPart, KeyRole>>;

/// A primary key and any associated signatures.
///
/// [See the module level documentation.](self)
pub type PrimaryKeyBundle<KeyPart> =
    KeyBundle<KeyPart, key::PrimaryRole>;

/// A subkey and any associated signatures.
///
/// [See the module level documentation.](self)
pub type SubkeyBundle<KeyPart>
    = KeyBundle<KeyPart, key::SubordinateRole>;

/// A User ID and any associated signatures.
///
/// [See the module level documentation.](self)
pub type UserIDBundle = ComponentBundle<UserID>;

/// A User Attribute and any associated signatures.
///
/// [See the module level documentation.](self)
pub type UserAttributeBundle = ComponentBundle<UserAttribute>;

/// An unknown component and any associated signatures.
///
/// Note: all signatures are stored as certifications.
///
/// [See the module level documentation.](self)
pub type UnknownBundle = ComponentBundle<Unknown>;


impl<C> Deref for ComponentBundle<C>
{
    type Target = C;

    fn deref(&self) -> &Self::Target {
        &self.component
    }
}

impl<C> ComponentBundle<C> {
    /// Returns a reference to the bundle's component.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// // Display some information about any unknown components.
    /// for u in cert.unknowns() {
    ///     eprintln!(" - {:?}", u.component());
    /// }
    /// # Ok(()) }
    /// ```
    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`.
    ///
    /// The active binding signature is the most recent, non-revoked
    /// self-signature that is valid according to the `policy` and
    /// alive at time `t` (`creation time <= t`, `t < expiry`).  If
    /// there are multiple such signatures then the signatures are
    /// ordered by their MPIs interpreted as byte strings.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// use openpgp::policy::StandardPolicy;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// let p = &StandardPolicy::new();
    ///
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// // Display information about each User ID's current active
    /// // binding signature (the `time` parameter is `None`), if any.
    /// for ua in cert.userids() {
    ///     eprintln!("{:?}", ua.binding_signature(p, None));
    /// }
    /// # Ok(()) }
    /// ```
    pub fn binding_signature<T>(&self, policy: &dyn Policy, t: T)
                                -> Result<&Signature>
        where T: Into<Option<time::SystemTime>>
    {
        let t = t.into().unwrap_or_else(crate::now);

        // 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`, or
        // that has been created at `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) => {
                        while i > 0
                            && self.self_signatures[i - 1].signature_creation_time()
                            == Some(t)
                        {
                            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,
                }
            };

        let mut sig = None;

        // Prefer the first error, which is the error arising from the
        // most recent binding signature that wasn't created after
        // `t`.
        let mut error = None;

        'next_sig: for s in self.self_signatures[i..].iter() {
            if let Err(e) = s.signature_alive(t, time::Duration::new(0, 0)) {
                // We know that t >= signature's creation time.  So,
                // it is expired.  But an older signature might not
                // be.  So, keep trying.
                if error.is_none() {
                    error = Some(e);
                }
                continue;
            }

            if let Err(e) = policy.signature(s, self.hash_algo_security)
            {
                if error.is_none() {
                    error = Some(e);
                }
                continue;
            }

            // The signature is good, but we may still need to verify the
            // back sig.
            if s.typ() == crate::types::SignatureType::SubkeyBinding &&
                s.key_flags().map(|kf| kf.for_signing()).unwrap_or(false)
            {
                let mut n = 0;
                let mut one_good_backsig = false;
                'next_backsig: for backsig in s.embedded_signatures() {
                    n += 1;
                    if let Err(e) = backsig.signature_alive(
                        t, time::Duration::new(0, 0))
                    {
                        // The primary key binding signature is not
                        // alive.
                        if error.is_none() {
                            error = Some(e);
                        }
                        continue 'next_backsig;
                    }

                    if let Err(e) = policy
                        .signature(backsig, self.hash_algo_security)
                    {
                        if error.is_none() {
                            error = Some(e);
                        }
                        continue 'next_backsig;
                    }

                    one_good_backsig = true;
                }

                if n == 0 {
                    // This shouldn't happen because
                    // Signature::verify_subkey_binding checks for the
                    // primary key binding signature.  But, better be
                    // safe.
                    if error.is_none() {
                        error = Some(Error::BadSignature(
                            "Primary key binding signature missing".into())
                                     .into());
                    }
                    continue 'next_sig;
                }

                if ! one_good_backsig {
                    continue 'next_sig;
                }
            }

            sig = Some(s);
            break;
        }

        if let Some(sig) = sig {
            Ok(sig)
        } else if let Some(err) = error {
            Err(err)
        } else {
            Err(Error::NoBindingSignature(t).into())
        }
    }

    /// Returns the component's self-signatures.
    ///
    /// The signatures are validated, and they are sorted by their
    /// creation time, most recent first.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// use openpgp::policy::StandardPolicy;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// let p = &StandardPolicy::new();
    ///
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// for (i, ka) in cert.keys().enumerate() {
    ///     eprintln!("Key #{} ({}) has {:?} self signatures",
    ///               i, ka.fingerprint(),
    ///               ka.bundle().self_signatures().len());
    /// }
    /// # Ok(()) }
    /// ```
    pub fn self_signatures(&self) -> &[Signature] {
        &self.self_signatures
    }

    /// Returns the component's third-party certifications.
    ///
    /// The signatures are *not* validated.  They are sorted by their
    /// creation time, most recent first.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// use openpgp::policy::StandardPolicy;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// let p = &StandardPolicy::new();
    ///
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// for ua in cert.userids() {
    ///     eprintln!("User ID {} has {:?} unverified, third-party certifications",
    ///               String::from_utf8_lossy(ua.userid().value()),
    ///               ua.bundle().certifications().len());
    /// }
    /// # Ok(()) }
    /// ```
    pub fn certifications(&self) -> &[Signature] {
        &self.certifications
    }

    /// Returns the component's revocations that were issued by the
    /// certificate holder.
    ///
    /// The revocations are validated, and they are sorted by their
    /// creation time, most recent first.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// use openpgp::policy::StandardPolicy;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// let p = &StandardPolicy::new();
    ///
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// for u in cert.userids() {
    ///     eprintln!("User ID {} has {:?} revocation certificates.",
    ///               String::from_utf8_lossy(u.userid().value()),
    ///               u.bundle().self_revocations().len());
    /// }
    /// # Ok(()) }
    /// ```
    pub fn self_revocations(&self) -> &[Signature] {
        &self.self_revocations
    }

    /// Returns the component's revocations that were issued by other
    /// certificates.
    ///
    /// The revocations are *not* validated.  They are sorted by their
    /// creation time, most recent first.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// use openpgp::policy::StandardPolicy;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// let p = &StandardPolicy::new();
    ///
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// for u in cert.userids() {
    ///     eprintln!("User ID {} has {:?} unverified, third-party revocation certificates.",
    ///               String::from_utf8_lossy(u.userid().value()),
    ///               u.bundle().other_revocations().len());
    /// }
    /// # Ok(()) }
    /// ```
    pub fn other_revocations(&self) -> &[Signature] {
        &self.other_revocations
    }

    /// Returns all of the component's Attestation Key Signatures.
    ///
    /// This feature is [experimental](crate#experimental-features).
    ///
    /// The signatures are validated, and they are sorted by their
    /// creation time, most recent first.
    ///
    /// A certificate owner can use Attestation Key Signatures to
    /// attest to third party certifications.  Currently, only userid
    /// and user attribute certifications can be attested.  See
    /// [Section 5.2.3.30 of RFC 4880bis] for details.
    ///
    ///   [Section 5.2.3.30 of RFC 4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-10.html#section-5.2.3.30
    ///
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # fn main() -> openpgp::Result<()> {
    /// # use openpgp::cert::prelude::*;
    /// use openpgp::policy::StandardPolicy;
    /// let p = &StandardPolicy::new();
    ///
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// for (i, uid) in cert.userids().enumerate() {
    ///     eprintln!("UserID #{} ({:?}) has {:?} attestation key signatures",
    ///               i, uid.email(),
    ///               uid.attestations().count());
    /// }
    /// # Ok(()) }
    /// ```
    pub fn attestations(&self)
                      -> impl Iterator<Item = &Signature> + Send + Sync
    {
        self.attestations.iter()
    }

    /// Returns all of the component's signatures.
    ///
    /// Only the self-signatures are validated.  The signatures are
    /// sorted first by type, then by creation time.  The self
    /// revocations come first, then the self signatures,
    /// then any key attestation signatures,
    /// certifications, and third-party revocations coming last.  This
    /// function may return additional types of signatures that could
    /// be associated to this component.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// use openpgp::policy::StandardPolicy;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// let p = &StandardPolicy::new();
    ///
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// for (i, ka) in cert.keys().enumerate() {
    ///     eprintln!("Key #{} ({}) has {:?} signatures",
    ///               i, ka.fingerprint(),
    ///               ka.signatures().count());
    /// }
    /// # Ok(()) }
    /// ```
    pub fn signatures(&self)
                      -> impl Iterator<Item = &Signature> + Send + Sync
    {
        self.self_revocations.iter()
            .chain(self.self_signatures.iter())
            .chain(self.attestations.iter())
            .chain(self.certifications.iter())
            .chain(self.other_revocations.iter())
    }

    /// 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 yet live at time `t`, and
    ///     even if there is a newer self-signature).
    ///
    /// selfsig must be the newest live self signature at time `t`.
    #[allow(clippy::blocks_in_if_conditions)]
    pub(crate) fn _revocation_status<'a, T>(&'a self, policy: &dyn Policy, t: T,
                                            hard_revocations_are_final: bool,
                                            selfsig: Option<&Signature>)
        -> RevocationStatus<'a>
        where T: Into<Option<time::SystemTime>>
    {
        // Fallback time.
        let time_zero = || time::UNIX_EPOCH;
        let t = t.into().unwrap_or_else(crate::now);
        let selfsig_creation_time
            = selfsig.and_then(|s| s.signature_creation_time())
                     .unwrap_or_else(time_zero);

        tracer!(super::TRACE, "ComponentBundle::_revocation_status", 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)).is_ok());
        }

        let check = |revs: &'a [Signature], sec: HashAlgoSecurity|
            -> Option<Vec<&'a Signature>>
        {
            let revs = revs.iter().filter(|rev| {
                if let Err(err) = policy.signature(rev, sec) {
                    t!("  revocation rejected by caller policy: {}", err);
                    false
                } else 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))));
                    true
                } else if selfsig_creation_time
                    > rev.signature_creation_time().unwrap_or_else(time_zero)
                {
                    // This comes after the hard revocation check,
                    // because a hard revocation is always valid.
                    t!("  newer binding signature trumps soft revocation ({:?} > {:?})",
                       selfsig_creation_time,
                       rev.signature_creation_time().unwrap_or_else(time_zero));
                    false
                } else if let Err(err)
                    = rev.signature_alive(t, time::Duration::new(0, 0))
                {
                    // This comes after the hard revocation check,
                    // because a hard revocation is always valid.
                    t!("  revocation not alive ({:?} - {:?}): {}",
                       rev.signature_creation_time().unwrap_or_else(time_zero),
                       rev.signature_validity_period()
                           .unwrap_or_else(|| time::Duration::new(0, 0)),
                       err);
                    false
                } 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))));
                    true
                }
            }).collect::<Vec<&Signature>>();

            if revs.is_empty() {
                None
            } else {
                Some(revs)
            }
        };

        if let Some(revs)
            = check(&self.self_revocations, self.hash_algo_security)
        {
            RevocationStatus::Revoked(revs)
        } else if let Some(revs)
            = check(&self.other_revocations, Default::default())
        {
            RevocationStatus::CouldBe(revs)
        } else {
            RevocationStatus::NotAsFarAsWeKnow
        }
    }

    /// Turns the `ComponentBundle` into an iterator over its
    /// `Packet`s.
    ///
    /// The signatures are ordered as follows:
    ///
    ///   - Self revocations,
    ///   - Self signatures,
    ///   - Third-party signatures, and
    ///   - Third-party revocations.
    ///
    /// For a given type of signature, the signatures are ordered by
    /// their creation time, most recent first.
    ///
    /// When turning the `Key` in a `KeyBundle` into a `Packet`, this
    /// function uses the component's type (`C`) to determine the
    /// packet's type; the type is not a function of whether the key
    /// has secret key material.
    pub(crate) fn into_packets(self)
                               -> impl Iterator<Item=Packet> + Send + Sync
        where Packet: From<C>
    {
        let p : Packet = self.component.into();
        std::iter::once(p)
            .chain(self.self_revocations.into_iter().map(|s| s.into()))
            .chain(self.self_signatures.into_iter().map(|s| s.into()))
            .chain(self.attestations.into_iter().map(|s| s.into()))
            .chain(self.certifications.into_iter().map(|s| s.into()))
            .chain(self.other_revocations.into_iter().map(|s| s.into()))
    }

    // Sorts and dedups the binding's signatures.
    //
    // Note: this uses Signature::normalized_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 merged as discussed in
    // Signature::merge.
    pub(crate) fn sort_and_dedup(&mut self)
    {
        // `same_bucket` function for Vec::dedup_by that compares
        // signatures and merges them if they are equal modulo
        // unhashed subpackets.
        fn sig_merge(a: &mut Signature, b: &mut Signature) -> bool {
            // If a == b, a is removed.  Hence, we merge into b.
            if a.normalized_eq(b) {
                b.merge_internal(a)
                    .expect("checked for equality above");
                true
            } else {
                false
            }
        }

        // If two signatures are merged, we also do some fixups.  Make
        // sure we also do this to signatures that are not merged, so
        // that `cert.merge(cert) == cert`.
        fn sig_fixup(sig: &mut Signature) {
            // Add missing issuer information.  This is a best effort
            // though.  If the unhashed area is full, there is nothing
            // we can do.
            let _ = sig.add_missing_issuers();

            // Merging Signatures sorts the unhashed subpacket area.
            // Do the same.
            sig.unhashed_area_mut().sort();
        }

        self.self_signatures.sort_by(Signature::normalized_cmp);
        self.self_signatures.dedup_by(sig_merge);
        // Order self signatures so that the most recent one comes
        // first.
        self.self_signatures.sort_by(sig_cmp);
        self.self_signatures.iter_mut().for_each(sig_fixup);

        self.attestations.sort_by(Signature::normalized_cmp);
        self.attestations.dedup_by(sig_merge);
        self.attestations.sort_by(sig_cmp);
        self.attestations.iter_mut().for_each(sig_fixup);

        self.certifications.sort_by(Signature::normalized_cmp);
        self.certifications.dedup_by(sig_merge);
        // There is no need to sort the certifications, but doing so
        // has the advantage that the most recent ones (and therefore
        // presumably the more relevant ones) come first.  Also,
        // cert::test::signature_order checks that the signatures are
        // sorted.
        self.certifications.sort_by(sig_cmp);
        self.certifications.iter_mut().for_each(sig_fixup);

        self.self_revocations.sort_by(Signature::normalized_cmp);
        self.self_revocations.dedup_by(sig_merge);
        self.self_revocations.sort_by(sig_cmp);
        self.self_revocations.iter_mut().for_each(sig_fixup);

        self.other_revocations.sort_by(Signature::normalized_cmp);
        self.other_revocations.dedup_by(sig_merge);
        self.other_revocations.sort_by(sig_cmp);
        self.other_revocations.iter_mut().for_each(sig_fixup);
    }
}

impl<P: key::KeyParts, R: key::KeyRole> ComponentBundle<Key<P, R>> {
    /// Returns a reference to the key.
    ///
    /// This is just a type-specific alias for
    /// [`ComponentBundle::component`].
    ///
    /// [`ComponentBundle::component`]: ComponentBundle::component()
    ///
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// // Display some information about the keys.
    /// for ka in cert.keys() {
    ///     eprintln!(" - {:?}", ka.key());
    /// }
    /// # Ok(()) }
    /// ```
    pub fn key(&self) -> &Key<P, R> {
        self.component()
    }

    /// Returns a mut reference to the key.
    pub(crate) fn key_mut(&mut self) -> &mut Key<P, R> {
        self.component_mut()
    }
}

impl<P: key::KeyParts> ComponentBundle<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.
    ///
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// use openpgp::policy::StandardPolicy;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// let p = &StandardPolicy::new();
    ///
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// // Display the subkeys' revocation status.
    /// for ka in cert.keys().subkeys() {
    ///     eprintln!(" Revocation status of {}: {:?}",
    ///               ka.fingerprint(), ka.revocation_status(p, None));
    /// }
    /// # Ok(()) }
    /// ```
    pub fn revocation_status<T>(&self, policy: &dyn Policy, t: T)
        -> RevocationStatus
        where T: Into<Option<time::SystemTime>>
    {
        let t = t.into();
        self._revocation_status(policy, t, true,
                                self.binding_signature(policy, t).ok())
    }
}

impl ComponentBundle<UserID> {
    /// Returns a reference to the User ID.
    ///
    /// This is just a type-specific alias for
    /// [`ComponentBundle::component`].
    ///
    /// [`ComponentBundle::component`]: ComponentBundle::component()
    ///
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// // Display some information about the User IDs.
    /// for ua in cert.userids() {
    ///     eprintln!(" - {:?}", ua.userid());
    /// }
    /// # Ok(()) }
    /// ```
    pub fn userid(&self) -> &UserID {
        self.component()
    }

    /// Returns the User ID's revocation status at time `t`.<a
    /// name="userid_revocation_status"></a>
    ///
    /// <!-- Why we have the above anchor:
    ///      https://github.com/rust-lang/rust/issues/71912 -->
    ///
    /// 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`.
    ///
    /// 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.
    //
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// use openpgp::policy::StandardPolicy;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// let p = &StandardPolicy::new();
    ///
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// // Display the User IDs' revocation status.
    /// for ua in cert.userids() {
    ///     eprintln!(" Revocation status of {}: {:?}",
    ///               String::from_utf8_lossy(ua.userid().value()),
    ///               ua.revocation_status(p, None));
    /// }
    /// # Ok(()) }
    /// ```
    pub fn revocation_status<T>(&self, policy: &dyn Policy, t: T)
        -> RevocationStatus
        where T: Into<Option<time::SystemTime>>
    {
        let t = t.into();
        self._revocation_status(policy, t, false, self.binding_signature(policy, t).ok())
    }
}

impl ComponentBundle<UserAttribute> {
    /// Returns a reference to the User Attribute.
    ///
    /// This is just a type-specific alias for
    /// [`ComponentBundle::component`].
    ///
    /// [`ComponentBundle::component`]: ComponentBundle::component()
    ///
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// // Display some information about the User Attributes
    /// for ua in cert.user_attributes() {
    ///     eprintln!(" - {:?}", ua.user_attribute());
    /// }
    /// # Ok(()) }
    /// ```
    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`.
    ///
    /// 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.
    //
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// use openpgp::policy::StandardPolicy;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// let p = &StandardPolicy::new();
    ///
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// // Display the User Attributes' revocation status.
    /// for (i, ua) in cert.user_attributes().enumerate() {
    ///     eprintln!(" Revocation status of User Attribute #{}: {:?}",
    ///               i, ua.revocation_status(p, None));
    /// }
    /// # Ok(()) }
    /// ```
    pub fn revocation_status<T>(&self, policy: &dyn Policy, t: T)
        -> RevocationStatus
        where T: Into<Option<time::SystemTime>>
    {
        let t = t.into();
        self._revocation_status(policy, t, false,
                                self.binding_signature(policy, t).ok())
    }
}

impl ComponentBundle<Unknown> {
    /// Returns a reference to the unknown component.
    ///
    /// This is just a type-specific alias for
    /// [`ComponentBundle::component`].
    ///
    /// [`ComponentBundle::component`]: ComponentBundle::component()
    ///
    /// # Examples
    ///
    /// ```
    /// # use sequoia_openpgp as openpgp;
    /// # use openpgp::cert::prelude::*;
    /// #
    /// # fn main() -> openpgp::Result<()> {
    /// # let (cert, _) =
    /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
    /// #     .generate()?;
    /// // Display some information about the User Attributes
    /// for u in cert.unknowns() {
    ///     eprintln!(" - {:?}", u.unknown());
    /// }
    /// # Ok(()) }
    /// ```
    pub fn unknown(&self) -> &Unknown {
        self.component()
    }
}