diff options
Diffstat (limited to 'openpgp/src/packet/key.rs')
-rw-r--r-- | openpgp/src/packet/key.rs | 2136 |
1 files changed, 2136 insertions, 0 deletions
diff --git a/openpgp/src/packet/key.rs b/openpgp/src/packet/key.rs new file mode 100644 index 00000000..dd12a98f --- /dev/null +++ b/openpgp/src/packet/key.rs @@ -0,0 +1,2136 @@ +//! Key-related functionality. +//! +//! # Data Types +//! +//! The main data type is the [`Key`] enum. This enum abstracts away +//! the differences between the key formats (the deprecated [version +//! 3], the current [version 4], and the proposed [version 5] +//! formats). Nevertheless, some functionality remains format +//! specific. For instance, the `Key` enum doesn't provide a +//! mechanism to generate keys. This functionality depends on the +//! format. +//! +//! This version of Sequoia only supports version 4 keys ([`Key4`]). +//! However, future versions may include limited support for version 3 +//! keys to allow working with archived messages, and we intend to add +//! support for version 5 keys once the new version of the +//! specification has been finalized. +//! +//! OpenPGP specifies four different types of keys: [public keys], +//! [secret keys], [public subkeys], and [secret subkeys]. These are +//! all represented by the `Key` enum and the `Key4` struct using +//! marker types. We use marker types rather than an enum, to better +//! exploit the type checking. For instance, type-specific methods +//! like [`Key::secret`] are only exposed for those types that +//! actually support them. See the documentation for [`Key`] for an +//! explanation of how the markers work. +//! +//! The [`SecretKeyMaterial`] data type allows working with secret key +//! material directly. This enum has two variants: [`Unencrypted`], +//! and [`Encrypted`]. It is not normally necessary to use this data +//! structure directly. The primary functionality that is of interest +//! to most users is decrypting secret key material. This is usually +//! more conveniently done using [`Key::decrypt_secret`]. +//! +//! [`Key`]: ../enum.Key.html +//! [`Key4`]: struct.Key4.html +//! [version 3]: https://tools.ietf.org/html/rfc1991#section-6.6 +//! [version 4]: https://tools.ietf.org/html/rfc4880#section-5.5.2 +//! [version 5]: https://www.ietf.org/id/draft-ietf-openpgp-rfc4880bis-09.html#name-public-key-packet-formats +//! [public keys]: https://tools.ietf.org/html/rfc4880#section-5.5.1.1 +//! [secret keys]: https://tools.ietf.org/html/rfc4880#section-5.5.1.3 +//! [public subkeys]: https://tools.ietf.org/html/rfc4880#section-5.5.1.2 +//! [secret subkeys]: https://tools.ietf.org/html/rfc4880#section-5.5.1.4 +//! [`Key::secret`]: ../enum.Key.html#method.secret +//! [`SecretKeyMaterial`]: enum.SecretKeyMaterial.html +//! [`Unencrypted`]: struct.Unencrypted.html +//! [`Encrypted`]: struct.Encrypted.html +//! [`Key::decrypt_secret`]: ../enum.Key.html#method.decrypt_secret +//! +//! # Key Creation +//! +//! Use [`Key4::generate_rsa`] or [`Key4::generate_ecc`] to create a +//! new key. +//! +//! Existing key material can be turned into an OpenPGP key using +//! [`Key4::import_public_cv25519`], [`Key4::import_public_ed25519`], +//! [`Key4::import_public_rsa`], [`Key4::import_secret_cv25519`], +//! [`Key4::import_secret_ed25519`], and [`Key4::import_secret_rsa`]. +//! +//! Whether you create a new key or import existing key material, you +//! still need to create a binding signature, and, for signing keys, a +//! back signature for the key to be usable. +//! +//! [`Key4::generate_rsa`]: struct.Key4.html#method.generate_rsa +//! [`Key4::generate_ecc`]: struct.Key4.html#method.generate_ecc +//! [`Key4::import_public_cv25519`]: struct.Key4.html#method.import_public_cv25519 +//! [`Key4::import_public_ed25519`]: struct.Key4.html#method.import_public_ed25519 +//! [`Key4::import_public_rsa`]: struct.Key4.html#method.import_public_rsa +//! [`Key4::import_secret_cv25519`]: struct.Key4.html#method.import_secret_cv25519 +//! [`Key4::import_secret_ed25519`]: struct.Key4.html#method.import_secret_ed25519 +//! [`Key4::import_secret_rsa`]: struct.Key4.html#method.import_secret_rsa +//! +//! # In-Memory Protection of Secret Key Material +//! +//! Whether the secret key material is protected on disk or not, +//! Sequoia encrypts unencrypted secret key material ([`Unencrypted`]) +//! while it is memory. This helps protect against [heartbleed]-style +//! attacks where a buffer over-read allows an attacker to read from +//! the process's address space. This protection is less important +//! for Rust programs, which are memory safe. However, it is +//! essential when Sequoia is used via its FFI. +//! +//! See [`crypto::mem::Encrypted`] for details. +//! +//! [`Unencrypted`]: struct.Unencrypted.html +//! [heartbleed]: https://en.wikipedia.org/wiki/Heartbleed +//! [`crypto::mem::Encrypted`]: ../../crypto/mem/struct.Encrypted.html + +use std::fmt; +use std::cmp::Ordering; +use std::convert::TryInto; +use std::time; + +#[cfg(any(test, feature = "quickcheck"))] +use quickcheck::{Arbitrary, Gen}; + +use crate::Error; +use crate::cert::prelude::*; +use crate::crypto::{self, mem::{self, Protected}, mpi, hash::Hash}; +use crate::packet; +use crate::packet::prelude::*; +use crate::PublicKeyAlgorithm; +use crate::SymmetricAlgorithm; +use crate::HashAlgorithm; +use crate::types::{Curve, Timestamp}; +use crate::crypto::S2K; +use crate::Result; +use crate::crypto::Password; +use crate::KeyID; +use crate::Fingerprint; +use crate::KeyHandle; + +mod conversions; + +/// A marker trait that captures whether a `Key` definitely contains +/// secret key material. +/// +/// A [`Key`] can be treated as if it only has public key material +/// ([`key::PublicParts`]) or also has secret key material +/// ([`key::SecretParts`]). For those cases where the type +/// information needs to be erased (e.g., interfaces like +/// [`Cert::keys`]), we provide the [`key::UnspecifiedParts`] marker. +/// +/// Even if a `Key` does not have the `SecretKey` marker, it may still +/// have secret key material. But, it will generally act as if it +/// didn't. In particular, when serializing a `Key` without the +/// `SecretKey` marker, secret key material will be ignored. See the +/// documentation for [`Key`] for a demonstration of this behavior. +/// +/// [`Cert::keys`]: ../../cert/struct.Cert.html#method.keys +/// [`Key`]: ../enum.Key.html +/// [`key::PublicParts`]: struct.PublicParts.html +/// [`key::SecretParts`]: struct.SecretParts.html +/// [`key::UnspecifiedParts`]: struct.UnspecifiedParts.html +pub trait KeyParts: fmt::Debug { + /// Converts a key with unspecified parts into this kind of key. + /// + /// This function is helpful when you need to convert a concrete + /// type into a generic type. Using `From` works, but requires + /// adding a type bound to the generic type, which is ugly and + /// invasive. + /// + /// Converting a key with [`key::PublicParts`] or + /// [`key::UnspecifiedParts`] will always succeed. However, + /// converting a key to one with [`key::SecretParts`] only + /// succeeds if the key actually contains secret key material. + /// + /// [`key::PublicParts`]: struct.PublicParts.html + /// [`key::UnspecifiedParts`]: struct.UnspecifiedParts.html + /// [`key::SecretParts`]: struct.SecretParts.html + /// + /// # Examples + /// + /// For a less construed example, refer to the [source code]: + /// + /// [source code]: https://gitlab.com/search?search=convert_key&project_id=4469613&search_code=true&repository_ref=master + /// + /// ``` + /// use sequoia_openpgp as openpgp; + /// use openpgp::Result; + /// # use openpgp::cert::prelude::*; + /// use openpgp::packet::prelude::*; + /// + /// fn f<P>(cert: &Cert, mut key: Key<P, key::UnspecifiedRole>) + /// -> Result<Key<P, key::UnspecifiedRole>> + /// where P: key::KeyParts + /// { + /// // ... + /// + /// # let criterium = true; + /// if criterium { + /// // Cert::primary_key's return type is concrete + /// // (Key<key::PublicParts, key::PrimaryRole>). We need to + /// // convert it to the generic type Key<P, key::UnspecifiedRole>. + /// // First, we "downcast" it to have unspecified parts and an + /// // unspecified role, then we use a method defined by the + /// // generic type to perform the conversion to the generic + /// // type P. + /// key = P::convert_key( + /// cert.primary_key().key().clone() + /// .parts_into_unspecified() + /// .role_into_unspecified())?; + /// } + /// # else { unreachable!() } + /// + /// // ... + /// + /// Ok(key) + /// } + /// # fn main() -> openpgp::Result<()> { + /// # let (cert, _) = + /// # CertBuilder::general_purpose(None, Some("alice@example.org")) + /// # .generate()?; + /// # f(&cert, cert.primary_key().key().clone().role_into_unspecified()).unwrap(); + /// # Ok(()) + /// # } + /// ``` + fn convert_key<R: KeyRole>(key: Key<UnspecifiedParts, R>) + -> Result<Key<Self, R>> + where Self: Sized; + + /// Converts a key reference with unspecified parts into this kind + /// of key reference. + /// + /// This function is helpful when you need to convert a concrete + /// type into a generic type. Using `From` works, but requires + /// adding a type bound to the generic type, which is ugly and + /// invasive. + /// + /// Converting a key with [`key::PublicParts`] or + /// [`key::UnspecifiedParts`] will always succeed. However, + /// converting a key to one with [`key::SecretParts`] only + /// succeeds if the key actually contains secret key material. + /// + /// [`key::PublicParts`]: struct.PublicParts.html + /// [`key::UnspecifiedParts`]: struct.UnspecifiedParts.html + /// [`key::SecretParts`]: struct.SecretParts.html + fn convert_key_ref<R: KeyRole>(key: &Key<UnspecifiedParts, R>) + -> Result<&Key<Self, R>> + where Self: Sized; + + /// Converts a key bundle with unspecified parts into this kind of + /// key bundle. + /// + /// This function is helpful when you need to convert a concrete + /// type into a generic type. Using `From` works, but requires + /// adding a type bound to the generic type, which is ugly and + /// invasive. + /// + /// Converting a key bundle with [`key::PublicParts`] or + /// [`key::UnspecifiedParts`] will always succeed. However, + /// converting a key bundle to one with [`key::SecretParts`] only + /// succeeds if the key bundle actually contains secret key + /// material. + /// + /// [`key::PublicParts`]: struct.PublicParts.html + /// [`key::UnspecifiedParts`]: struct.UnspecifiedParts.html + /// [`key::SecretParts`]: struct.SecretParts.html + fn convert_bundle<R: KeyRole>(bundle: KeyBundle<UnspecifiedParts, R>) + -> Result<KeyBundle<Self, R>> + where Self: Sized; + + /// Converts a key bundle reference with unspecified parts into + /// this kind of key bundle reference. + /// + /// This function is helpful when you need to convert a concrete + /// type into a generic type. Using `From` works, but requires + /// adding a type bound to the generic type, which is ugly and + /// invasive. + /// + /// Converting a key bundle with [`key::PublicParts`] or + /// [`key::UnspecifiedParts`] will always succeed. However, + /// converting a key bundle to one with [`key::SecretParts`] only + /// succeeds if the key bundle actually contains secret key + /// material. + /// + /// [`key::PublicParts`]: struct.PublicParts.html + /// [`key::UnspecifiedParts`]: struct.UnspecifiedParts.html + /// [`key::SecretParts`]: struct.SecretParts.html + fn convert_bundle_ref<R: KeyRole>(bundle: &KeyBundle<UnspecifiedParts, R>) + -> Result<&KeyBundle<Self, R>> + where Self: Sized; + + /// Converts a key amalgamation with unspecified parts into this + /// kind of key amalgamation. + /// + /// This function is helpful when you need to convert a concrete + /// type into a generic type. Using `From` works, but requires + /// adding a type bound to the generic type, which is ugly and + /// invasive. + /// + /// Converting a key amalgamation with [`key::PublicParts`] or + /// [`key::UnspecifiedParts`] will always succeed. However, + /// converting a key amalgamation to one with [`key::SecretParts`] + /// only succeeds if the key amalgamation actually contains secret + /// key material. + /// + /// [`key::PublicParts`]: struct.PublicParts.html + /// [`key::UnspecifiedParts`]: struct.UnspecifiedParts.html + /// [`key::SecretParts`]: struct.SecretParts.html + fn convert_key_amalgamation<'a, R: KeyRole>( + ka: ComponentAmalgamation<'a, Key<UnspecifiedParts, R>>) + -> Result<ComponentAmalgamation<'a, Key<Self, R>>> + where Self: Sized; + + /// Converts a key amalgamation reference with unspecified parts + /// into this kind of key amalgamation reference. + /// + /// This function is helpful when you need to convert a concrete + /// type into a generic type. Using `From` works, but requires + /// adding a type bound to the generic type, which is ugly and + /// invasive. + /// + /// Converting a key amalgamation with [`key::PublicParts`] or + /// [`key::UnspecifiedParts`] will always succeed. However, + /// converting a key amalgamation to one with [`key::SecretParts`] + /// only succeeds if the key amalgamation actually contains secret + /// key material. + /// + /// [`key::PublicParts`]: struct.PublicParts.html + /// [`key::UnspecifiedParts`]: struct.UnspecifiedParts.html + /// [`key::SecretParts`]: struct.SecretParts.html + fn convert_key_amalgamation_ref<'a, R: KeyRole>( + ka: &'a ComponentAmalgamation<'a, Key<UnspecifiedParts, R>>) + -> Result<&'a ComponentAmalgamation<'a, Key<Self, R>>> + where Self: Sized; +} + +/// A marker trait that captures a `Key`'s role. +/// +/// A [`Key`] can either be a primary key ([`key::PrimaryRole`]) or a +/// subordinate key ([`key::SubordinateRole`]). For those cases where +/// the type information needs to be erased (e.g., interfaces like +/// [`Cert::keys`]), we provide the [`key::UnspecifiedRole`] marker. +/// +/// [`Key`]: ../enum.Key.html +/// [`key::PrimaryRole`]: struct.PrimaryRole.html +/// [`key::SubordinateRole`]: struct.SubordinateRole.html +/// [`Cert::keys`]: ../../cert/struct.Cert.html#method.keys +/// [`key::UnspecifiedRole`]: struct.UnspecifiedRole.html +pub trait KeyRole: fmt::Debug { + /// Converts a key with an unspecified role into this kind of key. + /// + /// This function is helpful when you need to convert a concrete + /// type into a generic type. Using `From` works, but requires + /// adding a type bound to the generic type, which is ugly and + /// invasive. + /// + /// # Examples + /// + /// ``` + /// use sequoia_openpgp as openpgp; + /// use openpgp::Result; + /// # use openpgp::cert::prelude::*; + /// use openpgp::packet::prelude::*; + /// + /// fn f<R>(cert: &Cert, mut key: Key<key::UnspecifiedParts, R>) + /// -> Result<Key<key::UnspecifiedParts, R>> + /// where R: key::KeyRole + /// { + /// // ... + /// + /// # let criterium = true; + /// if criterium { + /// // Cert::primary_key's return type is concrete + /// // (Key<key::PublicParts, key::PrimaryRole>). We need to + /// // convert it to the generic type Key<key::UnspecifiedParts, R>. + /// // First, we "downcast" it to have unspecified parts and an + /// // unspecified role, then we use a method defined by the + /// // generic type to perform the conversion to the generic + /// // type R. + /// key = R::convert_key( + /// cert.primary_key().key().clone() + /// .parts_into_unspecified() + /// .role_into_unspecified()); + /// } + /// # else { unreachable!() } + /// + /// // ... + /// + /// Ok(key) + /// } + /// # fn main() -> openpgp::Result<()> { + /// # let (cert, _) = + /// # CertBuilder::general_purpose(None, Some("alice@example.org")) + /// # .generate()?; + /// # f(&cert, cert.primary_key().key().clone().parts_into_unspecified()).unwrap(); + /// # Ok(()) + /// # } + /// ``` + fn convert_key<P: KeyParts>(key: Key<P, UnspecifiedRole>) + -> Key<P, Self> + where Self: Sized; + + /// Converts a key reference with an unspecified role into this + /// kind of key reference. + /// + /// This function is helpful when you need to convert a concrete + /// type into a generic type. Using `From` works, but requires + /// adding a type bound to the generic type, which is ugly and + /// invasive. + fn convert_key_ref<P: KeyParts>(key: &Key<P, UnspecifiedRole>) + -> &Key<P, Self> + where Self: Sized; + + /// Converts a key bundle with an unspecified role into this kind + /// of key bundle. + /// + /// This function is helpful when you need to convert a concrete + /// type into a generic type. Using `From` works, but requires + /// adding a type bound to the generic type, which is ugly and + /// invasive. + fn convert_bundle<P: KeyParts>(bundle: KeyBundle<P, UnspecifiedRole>) + -> KeyBundle<P, Self> + where Self: Sized; + + /// Converts a key bundle reference with an unspecified role into + /// this kind of key bundle reference. + /// + /// This function is helpful when you need to convert a concrete + /// type into a generic type. Using `From` works, but requires + /// adding a type bound to the generic type, which is ugly and + /// invasive. + fn convert_bundle_ref<P: KeyParts>(bundle: &KeyBundle<P, UnspecifiedRole>) + -> &KeyBundle<P, Self> + where Self: Sized; +} + +/// A marker that indicates that a `Key` should be treated like a +/// public key. +/// +/// Note: this doesn't indicate whether the data structure contains +/// secret key material; it indicates whether any secret key material +/// should be ignored. For instance, when exporting a key with the +/// `PublicParts` marker, secret key material will *not* be exported. +/// See the documentation for [`Key`] for a demonstration. +/// +/// Refer to [`KeyParts`] for details. +/// +/// [`Key`]: ../enum.Key.html +/// [`KeyParts`]: trait.KeyParts.html +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct PublicParts; +impl KeyParts for PublicParts { + fn convert_key<R: KeyRole>(key: Key<UnspecifiedParts, R>) + -> Result<Key<Self, R>> { + Ok(key.into()) + } + + fn convert_key_ref<R: KeyRole>(key: &Key<UnspecifiedParts, R>) + -> Result<&Key<Self, R>> { + Ok(key.into()) + } + + fn convert_bundle<R: KeyRole>(bundle: KeyBundle<UnspecifiedParts, R>) + -> Result<KeyBundle<Self, R>> { + Ok(bundle.into()) + } + + fn convert_bundle_ref<R: KeyRole>(bundle: &KeyBundle<UnspecifiedParts, R>) + -> Result<&KeyBundle<Self, R>> { + Ok(bundle.into()) + } + + fn convert_key_amalgamation<'a, R: KeyRole>( + ka: ComponentAmalgamation<'a, Key<UnspecifiedParts, R>>) + -> Result<ComponentAmalgamation<'a, Key<Self, R>>> { + Ok(ka.into()) + } + + fn convert_key_amalgamation_ref<'a, R: KeyRole>( + ka: &'a ComponentAmalgamation<'a, Key<UnspecifiedParts, R>>) + -> Result<&'a ComponentAmalgamation<'a, Key<Self, R>>> { + Ok(ka.into()) + } +} + +/// A marker that indicates that a `Key` should be treated like a +/// secret key. +/// +/// Unlike the [`key::PublicParts`] marker, this marker asserts that +/// the [`Key`] contains secret key material. Because secret key +/// material is not protected by the self-signature, there is no +/// indication that the secret key material is actually valid. +/// +/// Refer to [`KeyParts`] for details. +/// +/// [`key::PublicParts`]: struct.PublicParts.html +/// [`Key`]: ../enum.Key.html +/// [`KeyParts`]: trait.KeyParts.html +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct SecretParts; +impl KeyParts for SecretParts { + fn convert_key<R: KeyRole>(key: Key<UnspecifiedParts, R>) + -> Result<Key<Self, R>>{ + key.try_into() + } + + fn convert_key_ref<R: KeyRole>(key: &Key<UnspecifiedParts, R>) + -> Result<&Key<Self, R>> { + key.try_into() + } + + fn convert_bundle<R: KeyRole>(bundle: KeyBundle<UnspecifiedParts, R>) + -> Result<KeyBundle<Self, R>> { + bundle.try_into() + } + + fn convert_bundle_ref<R: KeyRole>(bundle: &KeyBundle<UnspecifiedParts, R>) + -> Result<&KeyBundle<Self, R>> { + bundle.try_into() + } + + fn convert_key_amalgamation<'a, R: KeyRole>( + ka: ComponentAmalgamation<'a, Key<UnspecifiedParts, R>>) + -> Result<ComponentAmalgamation<'a, Key<Self, R>>> { + ka.try_into() + } + + fn convert_key_amalgamation_ref<'a, R: KeyRole>( + ka: &'a ComponentAmalgamation<'a, Key<UnspecifiedParts, R>>) + -> Result<&'a ComponentAmalgamation<'a, Key<Self, R>>> { + ka.try_into() + } +} + +/// A marker that indicates that a `Key`'s parts are unspecified. +/// +/// Neither public key-specific nor secret key-specific operations are +/// allowed on these types of keys. For instance, it is not possible +/// to export a key with the `UnspecifiedParts` marker, because it is +/// unclear how to treat any secret key material. To export such a +/// key, you need to first change the marker to [`key::PublicParts`] +/// or [`key::SecretParts`]. +/// +/// This marker is used when it is necessary to erase the type. For +/// instance, we need to do this when mixing [`Key`]s with different +/// markers in the same collection. See [`Cert::keys`] for an +/// example. +/// +/// Refer to [`KeyParts`] for details. +/// +/// [`key::PublicParts`]: struct.PublicParts.html +/// [`key::SecretParts`]: struct.SecretParts.html +/// [`KeyParts`]: trait.KeyParts.html +/// [`Key`]: ../enum.Key.html +/// [`Cert::keys`]: ../../struct.Cert.html#method.keys +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct UnspecifiedParts; +impl KeyParts for UnspecifiedParts { + fn convert_key<R: KeyRole>(key: Key<UnspecifiedParts, R>) + -> Result<Key<Self, R>> { + Ok(key) + } + + fn convert_key_ref<R: KeyRole>(key: &Key<UnspecifiedParts, R>) + -> Result<&Key<Self, R>> { + Ok(key) + } + + fn convert_bundle<R: KeyRole>(bundle: KeyBundle<UnspecifiedParts, R>) + -> Result<KeyBundle<Self, R>> { + Ok(bundle) + } + + fn convert_bundle_ref<R: KeyRole>(bundle: &KeyBundle<UnspecifiedParts, R>) + -> Result<&KeyBundle<Self, R>> { + Ok(bundle) + } + + fn convert_key_amalgamation<'a, R: KeyRole>( + ka: ComponentAmalgamation<'a, Key<UnspecifiedParts, R>>) + -> Result<ComponentAmalgamation<'a, Key<UnspecifiedParts, R>>> { + Ok(ka.into()) + } + + fn convert_key_amalgamation_ref<'a, R: KeyRole>( + ka: &'a ComponentAmalgamation<'a, Key<UnspecifiedParts, R>>) + -> Result<&'a ComponentAmalgamation<'a, Key<Self, R>>> { + Ok(ka.into()) + } +} + +/// A marker that indicates the `Key` should be treated like a primary key. +/// +/// Refer to [`KeyRole`] for details. +/// +/// [`KeyRole`]: trait.KeyRole.html +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct PrimaryRole; +impl KeyRole for PrimaryRole { + fn convert_key<P: KeyParts>(key: Key<P, UnspecifiedRole>) + -> Key<P, Self> { + key.into() + } + + fn convert_key_ref<P: KeyParts>(key: &Key<P, UnspecifiedRole>) + -> &Key<P, Self> { + key.into() + } + + fn convert_bundle<P: KeyParts>(bundle: KeyBundle<P, UnspecifiedRole>) + -> KeyBundle<P, Self> { + bundle.into() + } + + fn convert_bundle_ref<P: KeyParts>(bundle: &KeyBundle<P, UnspecifiedRole>) + -> &KeyBundle<P, Self> { + bundle.into() + } +} + +/// A marker that indicates the `Key` should treated like a subkey. +/// +/// Refer to [`KeyRole`] for details. +/// +/// [`KeyRole`]: trait.KeyRole.html +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct SubordinateRole; +impl KeyRole for SubordinateRole { + fn convert_key<P: KeyParts>(key: Key<P, UnspecifiedRole>) + -> Key<P, Self> { + key.into() + } + + fn convert_key_ref<P: KeyParts>(key: &Key<P, UnspecifiedRole>) + -> &Key<P, Self> { + key.into() + } + + fn convert_bundle<P: KeyParts>(bundle: KeyBundle<P, UnspecifiedRole>) + -> KeyBundle<P, Self> { + bundle.into() + } + + fn convert_bundle_ref<P: KeyParts>(bundle: &KeyBundle<P, UnspecifiedRole>) + -> &KeyBundle<P, Self> { + bundle.into() + } +} + +/// A marker that indicates the `Key`'s role is unspecified. +/// +/// Neither primary key-specific nor subkey-specific operations are +/// allowed. To perform those operations, the marker first has to be +/// changed to either [`key::PrimaryRole`] or +/// [`key::SubordinateRole`], as appropriate. +/// +/// Refer to [`KeyRole`] for details. +/// +/// [`key::PrimaryRole`]: struct.PrimaryRole.html +/// [`key::SubordinateRole`]: struct.SubordinateRole.html +/// [`KeyRole`]: trait.KeyRole.html +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct UnspecifiedRole; +impl KeyRole for UnspecifiedRole { + fn convert_key<P: KeyParts>(key: Key<P, UnspecifiedRole>) + -> Key<P, Self> { + key + } + + fn convert_key_ref<P: KeyParts>(key: &Key<P, UnspecifiedRole>) + -> &Key<P, Self> { + key + } + + fn convert_bundle<P: KeyParts>(bundle: KeyBundle<P, UnspecifiedRole>) + -> KeyBundle<P, Self> { + bundle + } + + fn convert_bundle_ref<P: KeyParts>(bundle: &KeyBundle<P, UnspecifiedRole>) + -> &KeyBundle<P, Self> { + bundle + } +} + +/// A Public Key. +pub(crate) type PublicKey = Key<PublicParts, PrimaryRole>; +/// A Public Subkey. +pub(crate) type PublicSubkey = Key<PublicParts, SubordinateRole>; +/// A Secret Key. +pub(crate) type SecretKey = Key<SecretParts, PrimaryRole>; +/// A Secret Subkey. +pub(crate) type SecretSubkey = Key<SecretParts, SubordinateRole>; + +/// A key with public parts, and an unspecified role +/// (`UnspecifiedRole`). +#[allow(dead_code)] +pub(crate) type UnspecifiedPublic = Key<PublicParts, UnspecifiedRole>; +/// A key with secret parts, and an unspecified role +/// (`UnspecifiedRole`). +pub(crate) type UnspecifiedSecret = Key<SecretParts, UnspecifiedRole>; + +/// A primary key with unspecified parts (`UnspecifiedParts`). +#[allow(dead_code)] +pub(crate) type UnspecifiedPrimary = Key<UnspecifiedParts, PrimaryRole>; +/// A subkey key with unspecified parts (`UnspecifiedParts`). +#[allow(dead_code)] +pub(crate) type UnspecifiedSecondary = Key<UnspecifiedParts, SubordinateRole>; + +/// A key whose parts and role are unspecified +/// (`UnspecifiedParts`, `UnspecifiedRole`). +#[allow(dead_code)] +pub(crate) type UnspecifiedKey = Key<UnspecifiedParts, UnspecifiedRole>; + + +/// Holds a public key, public subkey, private key or private subkey +/// packet. +/// +/// Use [`Key4::generate_rsa`] or [`Key4::generate_ecc`] to create a +/// new key. +/// +/// Existing key material can be turned into an OpenPGP key using +/// [`Key4::with_secret`], [`Key4::import_public_cv25519`], +/// [`Key4::import_public_ed25519`], [`Key4::import_public_rsa`], +/// [`Key4::import_secret_cv25519`], [`Key4::import_secret_ed25519`], +/// and [`Key4::import_secret_rsa`]. +/// +/// Whether you create a new key or import existing key material, you +/// still need to create a binding signature, and, for signing keys, a +/// back signature before integrating the key into a certificate. +/// +/// Normally, you won't directly use `Key4`, but [`Key`], which is a +/// relatively thin wrapper around `Key4`. +/// +/// See [Section 5.5 of RFC 4880] and [the documentation for `Key`] +/// for more details. +/// +/// [`Key4::with_secret`]: #method.with_secret +/// [`Key4::generate_rsa`]: #method.generate_rsa +/// [`Key4::generate_ecc`]: #method.generate_ecc +/// [`Key4::import_public_cv25519`]: #method.import_public_cv25519 +/// [`Key4::import_public_ed25519`]: #method.import_public_ed25519 +/// [`Key4::import_public_rsa`]: #method.import_public_rsa +/// [`Key4::import_secret_cv25519`]: #method.import_secret_cv25519 +/// [`Key4::import_secret_ed25519`]: #method.import_secret_ed25519 +/// [`Key4::import_secret_rsa`]: #method.import_secret_rsa +/// [Section 5.5 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.5 +/// [the documentation for `Key`]: ../enum.Key.html +/// [`Key`]: ../enum.Key.html +#[derive(Clone)] +pub struct Key4<P, R> + where P: KeyParts, R: KeyRole +{ + /// CTB packet header fields. + pub(crate) common: packet::Common, + /// When the key was created. + creation_time: Timestamp, + /// Public key algorithm of this signature. + pk_algo: PublicKeyAlgorithm, + /// Public key MPIs. + mpis: mpi::PublicKey, + /// Optional secret part of the key. + secret: Option<SecretKeyMaterial>, + + p: std::marker::PhantomData<P>, + r: std::marker::PhantomData<R>, +} + +impl<P: KeyParts, R: KeyRole> PartialEq for Key4<P, R> { + fn eq(&self, other: &Key4<P, R>) -> bool { + self.creation_time == other.creation_time + && self.pk_algo == other.pk_algo + && self.mpis == other.mpis + && self.secret == other.secret + } +} + +impl<P: KeyParts, R: KeyRole> Eq for Key4<P, R> {} + +impl<P: KeyParts, R: KeyRole> std::hash::H |