summaryrefslogtreecommitdiffstats
path: root/openpgp/src/packet/key.rs
diff options
context:
space:
mode:
Diffstat (limited to 'openpgp/src/packet/key.rs')
-rw-r--r--openpgp/src/packet/key.rs2136
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