//! Key amalgamations.
//!
//! Whereas a `KeyBundle` groups a `Key` with its self signatures, its
//! third-party signatures, and its revocation certificates, a
//! `KeyAmalgamation` groups a `KeyBundle` with all of the necessary
//! context needed to correctly implement relevant key-related
//! functionality. Specifically, a `KeyAmalgamation` includes a
//! reference to the `KeyBundle`, a reference to the containing
//! certificate, and the key's role (primary or subordinate).
//!
//! There are two notable differences between `KeyBundle`s and
//! `KeyAmalgamation`s. First, whereas a `KeyBundle`'s role is
//! primarily a marker, a `KeyAmalgamation`'s role determines the
//! `KeyAmalgamation`'s semantics. As such, it is not possible to
//! convert a `PrimaryKeyAmalgamation` to a `SubordinateAmalgamation`,
//! and vice versa. Second, a `KeyBundle`, owns its data, but a
//! `KeyAmalgamation` only references the contained data.
//!
//! There are three `KeyAmalgamation` variants:
//! `PrimaryKeyAmalgamation`, `SubordinateKeyAmalgamation`, and
//! `ErasedKeyAmalgamation`. Unlike a `Key` or a `KeyBundle` with an
//! `UnspecifiedRole`, an `ErasedKeyAmalgamation` remembers its role.
//! This means that an `ErasedKeyAmalgamation` implements the correct
//! semantics even though the role marker has been erased (hence the
//! name).
//!
//! `ErasedKeyAmalgamation`s are returned by `Cert::keys`.
//! `Cert::keys` can't return a more specific type, because it returns
//! an iterator that can contain both primary and subordinate keys.
//! The reason that we use a concrete type instead of a trait object
//! is so that when the user converts a `KeyAmalgamation` to a
//! `ValidKeyAmalgamation`, the `ValidKeyAmalgamation` retains the
//! type information about the role. Preserving this type information
//! increases type safety for users of this API.
use std::time;
use std::time::SystemTime;
use std::ops::Deref;
use std::convert::TryFrom;
use std::convert::TryInto;
use anyhow::Context;
use crate::{
Cert,
cert::components::KeyBundle,
cert::amalgamation::{
ComponentAmalgamation,
ValidAmalgamation,
ValidateAmalgamation,
},
cert::ValidCert,
crypto::{hash::Hash, Signer},
Error,
Packet,
packet::Key,
packet::key,
packet::key::KeyParts,
packet::signature,
packet::Signature,
policy::Policy,
Result,
SignatureType,
types::HashAlgorithm,
types::RevocationStatus,
};
/// Methods specific to key amalgamations.
// This trait exists primarily so that `ValidAmalgamation` can depend
// on it, and use it in its default implementations.
pub trait Primary<'a, P, R>
where P: 'a + key::KeyParts,
R: 'a + key::KeyRole,
{
/// Returns whether the key amalgamation is a primary key
/// amalgamation.
fn primary(&self) -> bool;
}
/// A key amalgamation.
///
/// Generally, you won't use this type directly, but instead use
/// `PrimaryKeyAmalgamation`, `SubordinateKeyAmalgamation`, or
/// `ErasedKeyAmalgamation`.
///
/// See the module-level documentation for information about key
/// amalgamations.
#[derive(Debug)]
pub struct KeyAmalgamation<'a, P, R, R2>
where P: 'a + key::KeyParts,
R: 'a + key::KeyRole,
{
ca: ComponentAmalgamation<'a, Key<P, R>>,
primary: R2,
}
// derive(Clone) doesn't work with generic parameters that don't
// implement clone. But, we don't need to require that C implements
// Clone, because we're not cloning C, just the reference.
//
// See: https://github.com/rust-lang/rust/issues/26925
impl<'a, P, R, R2> Clone for KeyAmalgamation<'a, P, R, R2>
where P: 'a + key::KeyParts,
R: 'a + key::KeyRole,
R2: Copy,
{
fn clone(&self) -> Self {
Self {