summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2020-08-07 23:42:51 +0200
committerNeal H. Walfield <neal@pep.foundation>2020-08-12 09:25:07 +0200
commit9a5f5b44335240daac54fa8eb9efa2a8fff9fd27 (patch)
treec97414c25274e2283c5e4ad5d1d0e5bdbb4ba211
parenta0b4afd578e1cd76aa2d82bdf7d53d20d9ec6965 (diff)
openpgp: Improve documentation for SignatureBuilder finalizers.
- Improve the documentation of and add examples for the various `SignatureBuilder` finalizers.
-rw-r--r--openpgp/src/packet/signature/mod.rs889
1 files changed, 844 insertions, 45 deletions
diff --git a/openpgp/src/packet/signature/mod.rs b/openpgp/src/packet/signature/mod.rs
index 8fae4a5c..87d9e56c 100644
--- a/openpgp/src/packet/signature/mod.rs
+++ b/openpgp/src/packet/signature/mod.rs
@@ -234,12 +234,84 @@ impl SignatureBuilder {
self
}
- /// Creates a standalone signature.
+ /// Generates a standalone signature.
///
- /// The Signature's public-key algorithm field is set to the
+ /// A [Standalone Signature] ([`SignatureType::Standalone`]) is a
+ /// self-contained signature, which is only over the signature
+ /// packet.
+ ///
+ /// [Standalone Signature]: https://tools.ietf.org/html/rfc4880#section-5.2.1
+ /// [`SignatureType::Standalone`]: ../../types/enum.SignatureType.html#variant.Standalone
+ ///
+ /// This function checks that the [signature type] (passed to
+ /// [`SignatureBuilder::new`], set via
+ /// [`SignatureBuilder::set_type`], or copied when using
+ /// `SignatureBuilder::From`) is [`SignatureType::Standalone`] or
+ /// [`SignatureType::Unknown`].
+ ///
+ /// [signature type]: ../../types/enum.SignatureType.html
+ /// [`SignatureBuilder::new`]: #method.new
+ /// [`SignatureBuilder::set_type`]: #method.set_type
+ /// [`SignatureType::Timestamp`]: ../../types/enum.SignatureType.html#variant.Timestamp
+ /// [`SignatureType::Unknown`]: ../../types/enum.SignatureType.html#variant.Unknown
+ ///
+ /// The [`Signature`]'s public-key algorithm field is set to the
/// algorithm used by `signer`.
- /// If not set before, Issuer and Issuer Fingerprint subpackets are added
- /// pointing to `signer`.
+ ///
+ /// [`Signature`]: ../enum.Signature.html
+ ///
+ /// If neither an [`Issuer`] subpacket (set using
+ /// [`SignatureBuilder::set_issuer`], for instance) nor an
+ /// [`Issuer Fingerprint`] subpacket (set using
+ /// [`SignatureBuilder::set_issuer_fingerprint`], for instance) is
+ /// set, they are both added to the new `Signature`'s unhashed
+ /// subpacket area and set to the `signer`'s `KeyID` and
+ /// `Fingerprint`, respectively.
+ ///
+ /// [`Issuer`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.5
+ /// [`SignatureBuilder::set_issuer`]: #method.set_issuer
+ /// [`Issuer Fingerprint`]: https://www.ietf.org/id/draft-ietf-openpgp-rfc4880bis-09.html#section-5.2.3.28
+ /// [`SignatureBuilder::set_issuer_fingerprint`]: #method.set_issuer_fingerprint
+ ///
+ /// Likewise, a [`Signature Creation Time`] subpacket set to the
+ /// current time is added to the hashed area if the `Signature
+ /// Creation Time` subpacket hasn't been set using, for instance,
+ /// the [`set_signature_creation_time`] method or the
+ /// [`preserve_signature_creation_time`] method.
+ ///
+ /// [`Signature Creation Time`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.4
+ /// [`set_signature_creation_time`]: #method.set_signature_creation_time
+ /// [`preserve_signature_creation_time`]: #method.preserve_signature_creation_time
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use sequoia_openpgp as openpgp;
+ /// use openpgp::cert::prelude::*;
+ /// use openpgp::packet::prelude::*;
+ /// use openpgp::policy::StandardPolicy;
+ /// use openpgp::types::SignatureType;
+ ///
+ /// # fn main() -> openpgp::Result<()> {
+ /// let p = &StandardPolicy::new();
+ ///
+ /// let (cert, _) = CertBuilder::new().add_signing_subkey().generate()?;
+ ///
+ /// // Get a usable (alive, non-revoked) signing key.
+ /// let key : &Key<_, _> = cert
+ /// .keys().with_policy(p, None)
+ /// .for_signing().alive().revoked(false).nth(0).unwrap().key();
+ /// // Derive a signer.
+ /// let mut signer = key.clone().parts_into_secret()?.into_keypair()?;
+ ///
+ /// let sig = SignatureBuilder::new(SignatureType::Standalone)
+ /// .sign_standalone(&mut signer)?;
+ ///
+ /// // Verify it.
+ /// sig.verify_standalone(signer.public())?;
+ /// # Ok(())
+ /// # }
+ /// ```
pub fn sign_standalone(mut self, signer: &mut dyn Signer)
-> Result<Signature>
{
@@ -256,12 +328,103 @@ impl SignatureBuilder {
self.sign(signer, digest)
}
- /// Creates a timestamp signature.
- ///
- /// The Signature's public-key algorithm field is set to the
+ /// Generates a Timestamp Signature.
+ ///
+ /// Like a [Standalone Signature] (created using
+ /// [`SignatureBuilder::sign_standalone`]), a [Timestamp
+ /// Signature] is a self-contained signature, but its emphasis in
+ /// on the contained timestamp, specifically, the timestamp stored
+ /// in the [`Signature Creation Time`] subpacket. This type of
+ /// signature is primarily used by [timestamping services]. To
+ /// timestamp a signature, you can include either a [Signature
+ /// Target subpacket] (set using
+ /// [`SignatureBuilder::set_signature_target`]), or an [Embedded
+ /// Signature] (set using
+ /// [`SignatureBuilder::set_embedded_signature`]) in the hashed
+ /// area.
+ ///
+ ///
+ /// [Standalone Signature]: https://tools.ietf.org/html/rfc4880#section-5.2.1
+ /// [`SignatureBuilder::sign_standalone`]: #method.sign_standalone
+ /// [Timestamp Signature]: https://tools.ietf.org/html/rfc4880#section-5.2.1
+ /// [`Signature Creation Time`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.4
+ /// [timestamping services]: https://en.wikipedia.org/wiki/Trusted_timestamping
+ /// [Signature Target subpacket]: https://tools.ietf.org/html/rfc4880#section-5.2.3.25
+ /// [`SignatureBuilder::set_signature_target`]: #method.set_signature_target
+ /// [Embedded Signature]: https://tools.ietf.org/html/rfc4880#section-5.2.3.26
+ /// [`SignatureBuilder::set_embedded_signature`]: #method.set_embedded_signature
+ ///
+ /// This function checks that the [signature type] (passed to
+ /// [`SignatureBuilder::new`], set via
+ /// [`SignatureBuilder::set_type`], or copied when using
+ /// `SignatureBuilder::From`) is [`SignatureType::Timestamp`] or
+ /// [`SignatureType::Unknown`].
+ ///
+ /// [signature type]: ../../types/enum.SignatureType.html
+ /// [`SignatureBuilder::new`]: #method.new
+ /// [`SignatureBuilder::set_type`]: #method.set_type
+ /// [`SignatureType::Timestamp`]: ../../types/enum.SignatureType.html#variant.Timestamp
+ /// [`SignatureType::Unknown`]: ../../types/enum.SignatureType.html#variant.Unknown
+ ///
+ /// The [`Signature`]'s public-key algorithm field is set to the
/// algorithm used by `signer`.
- /// If not set before, Issuer and Issuer Fingerprint subpackets are added
- /// pointing to `signer`.
+ ///
+ /// [`Signature`]: ../enum.Signature.html
+ ///
+ /// If neither an [`Issuer`] subpacket (set using
+ /// [`SignatureBuilder::set_issuer`], for instance) nor an
+ /// [`Issuer Fingerprint`] subpacket (set using
+ /// [`SignatureBuilder::set_issuer_fingerprint`], for instance) is
+ /// set, they are both added to the new `Signature`'s unhashed
+ /// subpacket area and set to the `signer`'s `KeyID` and
+ /// `Fingerprint`, respectively.
+ ///
+ /// [`Issuer`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.5
+ /// [`SignatureBuilder::set_issuer`]: #method.set_issuer
+ /// [`Issuer Fingerprint`]: https://www.ietf.org/id/draft-ietf-openpgp-rfc4880bis-09.html#section-5.2.3.28
+ /// [`SignatureBuilder::set_issuer_fingerprint`]: #method.set_issuer_fingerprint
+ ///
+ /// Likewise, a [`Signature Creation Time`] subpacket set to the
+ /// current time is added to the hashed area if the `Signature
+ /// Creation Time` subpacket hasn't been set using, for instance,
+ /// the [`set_signature_creation_time`] method or the
+ /// [`preserve_signature_creation_time`] method.
+ ///
+ /// [`Signature Creation Time`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.4
+ /// [`set_signature_creation_time`]: #method.set_signature_creation_time
+ /// [`preserve_signature_creation_time`]: #method.preserve_signature_creation_time
+ ///
+ /// # Examples
+ ///
+ /// Create a timestamp signature:
+ ///
+ /// ```
+ /// use sequoia_openpgp as openpgp;
+ /// use openpgp::cert::prelude::*;
+ /// use openpgp::packet::prelude::*;
+ /// use openpgp::policy::StandardPolicy;
+ /// use openpgp::types::SignatureType;
+ ///
+ /// # fn main() -> openpgp::Result<()> {
+ /// let p = &StandardPolicy::new();
+ ///
+ /// let (cert, _) = CertBuilder::new().add_signing_subkey().generate()?;
+ ///
+ /// // Get a usable (alive, non-revoked) signing key.
+ /// let key : &Key<_, _> = cert
+ /// .keys().with_policy(p, None)
+ /// .for_signing().alive().revoked(false).nth(0).unwrap().key();
+ /// // Derive a signer.
+ /// let mut signer = key.clone().parts_into_secret()?.into_keypair()?;
+ ///
+ /// let sig = SignatureBuilder::new(SignatureType::Timestamp)
+ /// .sign_timestamp(&mut signer)?;
+ ///
+ /// // Verify it.
+ /// sig.verify_timestamp(signer.public())?;
+ /// # Ok(())
+ /// # }
+ /// ```
pub fn sign_timestamp(mut self, signer: &mut dyn Signer)
-> Result<Signature>
{
@@ -278,12 +441,110 @@ impl SignatureBuilder {
self.sign(signer, digest)
}
- /// Signs `pk` using `signer`.
+ /// Generates a Direct Key Signature.
///
- /// The Signature's public-key algorithm field is set to the
+ /// A [Direct Key Signature] is a signature over the primary key.
+ /// It is primarily used to hold fallback [preferences]. For
+ /// instance, when addressing the Certificate by a User ID, the
+ /// OpenPGP implementation is supposed to look for preferences
+ /// like the [Preferred Symmetric Algorithms] on the User ID, and
+ /// only if there is no such packet, look on the direct key
+ /// signature.
+ ///
+ /// This function is also used to create a [Key Revocation
+ /// Signature], which revokes the certificate.
+ ///
+ /// [preferences]: ../../cert/trait.Preferences.html
+ /// [Direct Key Signature]: https://tools.ietf.org/html/rfc4880#section-5.2.1
+ /// [Preferred Symmetric Algorithms]: https://tools.ietf.org/html/rfc4880#section-5.2.3.7
+ /// [Key Revocation Signature]: https://tools.ietf.org/html/rfc4880#section-5.2.1
+ ///
+ /// This function checks that the [signature type] (passed to
+ /// [`SignatureBuilder::new`], set via
+ /// [`SignatureBuilder::set_type`], or copied when using
+ /// `SignatureBuilder::From`) is [`SignatureType::DirectKey`],
+ /// [`SignatureType::KeyRevocation`], or
+ /// [`SignatureType::Unknown`].
+ ///
+ /// [signature type]: ../../types/enum.SignatureType.html
+ /// [`SignatureBuilder::new`]: #method.new
+ /// [`SignatureBuilder::set_type`]: #method.set_type
+ /// [`SignatureType::DirectKey`]: ../../types/enum.SignatureType.html#variant.DirectKey
+ /// [`SignatureType::KeyRevocation`]: ../../types/enum.SignatureType.html#variant.KeyRevocation
+ /// [`SignatureType::Unknown`]: ../../types/enum.SignatureType.html#variant.Unknown
+ ///
+ /// The [`Signature`]'s public-key algorithm field is set to the
/// algorithm used by `signer`.
- /// If not set before, Issuer and Issuer Fingerprint subpackets are added
- /// pointing to `signer`.
+ ///
+ /// [`Signature`]: ../enum.Signature.html
+ ///
+ /// If neither an [`Issuer`] subpacket (set using
+ /// [`SignatureBuilder::set_issuer`], for instance) nor an
+ /// [`Issuer Fingerprint`] subpacket (set using
+ /// [`SignatureBuilder::set_issuer_fingerprint`], for instance) is
+ /// set, they are both added to the new `Signature`'s unhashed
+ /// subpacket area and set to the `signer`'s `KeyID` and
+ /// `Fingerprint`, respectively.
+ ///
+ /// [`Issuer`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.5
+ /// [`SignatureBuilder::set_issuer`]: #method.set_issuer
+ /// [`Issuer Fingerprint`]: https://www.ietf.org/id/draft-ietf-openpgp-rfc4880bis-09.html#section-5.2.3.28
+ /// [`SignatureBuilder::set_issuer_fingerprint`]: #method.set_issuer_fingerprint
+ ///
+ /// Likewise, a [`Signature Creation Time`] subpacket set to the
+ /// current time is added to the hashed area if the `Signature
+ /// Creation Time` subpacket hasn't been set using, for instance,
+ /// the [`set_signature_creation_time`] method or the
+ /// [`preserve_signature_creation_time`] method.
+ ///
+ /// [`Signature Creation Time`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.4
+ /// [`set_signature_creation_time`]: #method.set_signature_creation_time
+ /// [`preserve_signature_creation_time`]: #method.preserve_signature_creation_time
+ ///
+ /// # Examples
+ ///
+ /// Set the default value for the [Preferred Symmetric Algorithms
+ /// subpacket]:
+ ///
+ /// [Preferred Symmetric Algorithms subpacket]: #method.set_preferred_symmetric_algorithms
+ ///
+ /// ```
+ /// use sequoia_openpgp as openpgp;
+ /// use openpgp::cert::prelude::*;
+ /// use openpgp::packet::prelude::*;
+ /// use openpgp::policy::StandardPolicy;
+ /// use openpgp::types::SignatureType;
+ /// use openpgp::types::SymmetricAlgorithm;
+ ///
+ /// # fn main() -> openpgp::Result<()> {
+ /// let p = &StandardPolicy::new();
+ ///
+ /// let (cert, _) = CertBuilder::new().add_signing_subkey().generate()?;
+ ///
+ /// // Get a usable (alive, non-revoked) certification key.
+ /// let key : &Key<_, _> = cert
+ /// .keys().with_policy(p, None)
+ /// .for_certification().alive().revoked(false).nth(0).unwrap().key();
+ /// // Derive a signer.
+ /// let mut signer = key.clone().parts_into_secret()?.into_keypair()?;
+ ///
+ /// // A direct key signature is always over the primary key.
+ /// let pk = cert.primary_key().key();
+ ///
+ /// // Modify the existing direct key signature.
+ /// let sig = SignatureBuilder::from(
+ /// cert.with_policy(p, None)?.direct_key_signature()?.clone())
+ /// .set_preferred_symmetric_algorithms(
+ /// vec![ SymmetricAlgorithm::AES256,
+ /// SymmetricAlgorithm::AES128,
+ /// ])?
+ /// .sign_direct_key(&mut signer, pk)?;
+ ///
+ /// // Verify it.
+ /// sig.verify_direct_key(signer.public(), pk)?;
+ /// # Ok(())
+ /// # }
+ /// ```
pub fn sign_direct_key<P>(mut self, signer: &mut dyn Signer,
pk: &Key<P, key::PrimaryRole>)
-> Result<Signature>
@@ -303,12 +564,120 @@ impl SignatureBuilder {
self.sign(signer, digest)
}
- /// Signs binding between `userid` and `key` using `signer`.
- ///
- /// The Signature's public-key algorithm field is set to the
+ /// Generates a User ID binding signature.
+ ///
+ /// A User ID binding signature (a self signature) or a [User ID
+ /// certification] (a third-party signature) is a signature over a
+ /// `User ID` and a `Primary Key` made by a certification-capable
+ /// key. It asserts that the signer is convinced that the `User
+ /// ID` should be associated with the `Certificate`, i.e., that
+ /// the binding is authentic.
+ ///
+ /// [User ID certification]: https://tools.ietf.org/html/rfc4880#section-5.2.1
+ ///
+ /// OpenPGP has four types of `User ID` certifications. They are
+ /// intended to express the degree of the signer's conviction,
+ /// i.e., how well the signer authenticated the binding. In
+ /// practice, the `Positive Certification` type is used for
+ /// self-signatures, and the `Generic Certification` is used for
+ /// third-party certifications; the other types are not normally
+ /// used.
+ ///
+ /// This function is also used to create [Certification
+ /// Revocations].
+ ///
+ /// [Certification Revocations]: https://tools.ietf.org/html/rfc4880#section-5.2.1
+ ///
+ /// This function checks that the [signature type] (passed to
+ /// [`SignatureBuilder::new`], set via
+ /// [`SignatureBuilder::set_type`], or copied when using
+ /// `SignatureBuilder::From`) is [`GenericCertification`],
+ /// [`PersonaCertification`], [`CasualCertification`],
+ /// [`PositiveCertification`], [`CertificationRevocation`], or
+ /// [`SignatureType::Unknown`].
+ ///
+ /// [signature type]: ../../types/enum.SignatureType.html
+ /// [`SignatureBuilder::new`]: #method.new
+ /// [`SignatureBuilder::set_type`]: #method.set_type
+ /// [`GenericCertification`]: ../../types/enum.SignatureType.html#variant.GenericCertification
+ /// [`PersonaCertification`]: ../../types/enum.SignatureType.html#variant.PersonaCertification
+ /// [`CasualCertification`]: ../../types/enum.SignatureType.html#variant.CasualCertification
+ /// [`PositiveCertification`]: ../../types/enum.SignatureType.html#variant.PositiveCertification
+ /// [`CertificationRevocation`]: ../../types/enum.SignatureType.html#variant.CertificationRevocation
+ /// [`SignatureType::Unknown`]: ../../types/enum.SignatureType.html#variant.Unknown
+ ///
+ /// The [`Signature`]'s public-key algorithm field is set to the
/// algorithm used by `signer`.
- /// If not set before, Issuer and Issuer Fingerprint subpackets are added
- /// pointing to `signer`.
+ ///
+ /// [`Signature`]: ../enum.Signature.html
+ ///
+ /// If neither an [`Issuer`] subpacket (set using
+ /// [`SignatureBuilder::set_issuer`], for instance) nor an
+ /// [`Issuer Fingerprint`] subpacket (set using
+ /// [`SignatureBuilder::set_issuer_fingerprint`], for instance) is
+ /// set, they are both added to the new `Signature`'s unhashed
+ /// subpacket area and set to the `signer`'s `KeyID` and
+ /// `Fingerprint`, respectively.
+ ///
+ /// [`Issuer`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.5
+ /// [`SignatureBuilder::set_issuer`]: #method.set_issuer
+ /// [`Issuer Fingerprint`]: https://www.ietf.org/id/draft-ietf-openpgp-rfc4880bis-09.html#section-5.2.3.28
+ /// [`SignatureBuilder::set_issuer_fingerprint`]: #method.set_issuer_fingerprint
+ ///
+ /// Likewise, a [`Signature Creation Time`] subpacket set to the
+ /// current time is added to the hashed area if the `Signature
+ /// Creation Time` subpacket hasn't been set using, for instance,
+ /// the [`set_signature_creation_time`] method or the
+ /// [`preserve_signature_creation_time`] method.
+ ///
+ /// [`Signature Creation Time`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.4
+ /// [`set_signature_creation_time`]: #method.set_signature_creation_time
+ /// [`preserve_signature_creation_time`]: #method.preserve_signature_creation_time
+ ///
+ /// # Examples
+ ///
+ /// Set the [Preferred Symmetric Algorithms subpacket], which will
+ /// be used when addressing the certificate via the associated
+ /// User ID:
+ ///
+ /// [Preferred Symmetric Algorithms subpacket]: #method.set_preferred_symmetric_algorithms
+ ///
+ /// ```
+ /// use sequoia_openpgp as openpgp;
+ /// use openpgp::cert::prelude::*;
+ /// use openpgp::packet::prelude::*;
+ /// use openpgp::policy::StandardPolicy;
+ /// use openpgp::types::SymmetricAlgorithm;
+ ///
+ /// # fn main() -> openpgp::Result<()> {
+ /// let p = &StandardPolicy::new();
+ ///
+ /// let (cert, _) = CertBuilder::new().add_userid("Alice").generate()?;
+ ///
+ /// // Get a usable (alive, non-revoked) certification key.
+ /// let key : &Key<_, _> = cert
+ /// .keys().with_policy(p, None)
+ /// .for_certification().alive().revoked(false).nth(0).unwrap().key();
+ /// // Derive a signer.
+ /// let mut signer = key.clone().parts_into_secret()?.into_keypair()?;
+ ///
+ /// let pk = cert.primary_key().key();
+ ///
+ /// // Update the User ID's binding signature.
+ /// let ua = cert.with_policy(p, None)?.userids().nth(0).unwrap();
+ /// let new_sig = SignatureBuilder::from(
+ /// ua.binding_signature().clone())
+ /// .set_preferred_symmetric_algorithms(
+ /// vec![ SymmetricAlgorithm::AES256,
+ /// SymmetricAlgorithm::AES128,
+ /// ])?
+ /// .sign_userid_binding(&mut signer, pk, ua.userid())?;
+ ///
+ /// // Verify it.
+ /// new_sig.verify_userid_binding(signer.public(), pk, ua.userid())?;
+ /// # Ok(())
+ /// # }
+ /// ```
pub fn sign_userid_binding<P>(mut self, signer: &mut dyn Signer,
key: &Key<P, key::PrimaryRole>,
userid: &UserID)
@@ -332,18 +701,111 @@ impl SignatureBuilder {
self.sign(signer, digest)
}
- /// Signs subkey binding from `primary` to `subkey` using `signer`.
+ /// Generates a subkey binding signature.
+ ///
+ /// A [subkey binding signature] is a signature over the primary
+ /// key and a subkey, which is made by the primary key. It is an
+ /// assertion by the certificate that the subkey really belongs to
+ /// the certificate. That is, it binds the subkey to the
+ /// certificate.
+ ///
+ /// Note: this function does not create a back signature, which is
+ /// needed by certification-capable, signing-capable, and
+ /// authentication-capable subkeys. A back signature can be
+ /// created using [`SignatureBuilder::sign_primary_key_binding`].
+ ///
+ /// This function is also used to create subkey revocations.
///
- /// The Signature's public-key algorithm field is set to the
+ /// [subkey binding signature]: https://tools.ietf.org/html/rfc4880#section-5.2.1
+ /// [`SignatureBuilder::sign_primary_key_binding`]: #method.sign_primary_key_binding
+ ///
+ /// This function checks that the [signature type] (passed to
+ /// [`SignatureBuilder::new`], set via
+ /// [`SignatureBuilder::set_type`], or copied when using
+ /// `SignatureBuilder::From`) is
+ /// [`SignatureType::SubkeyBinding`], [`SignatureType::SubkeyRevocation`], or
+ /// [`SignatureType::Unknown`].
+ ///
+ /// [signature type]: ../../types/enum.SignatureType.html
+ /// [`SignatureBuilder::new`]: #method.new
+ /// [`SignatureBuilder::set_type`]: #method.set_type
+ /// [`SignatureType::SubkeyBinding`]: ../../types/enum.SignatureType.html#variant.SubkeyBinding
+ /// [`SignatureType::SubkeyRevocation`]: ../../types/enum.SignatureType.html#variant.SubkeyRevocation
+ /// [`SignatureType::Unknown`]: ../../types/enum.SignatureType.html#variant.Unknown
+ ///
+ /// The [`Signature`]'s public-key algorithm field is set to the
/// algorithm used by `signer`.
- /// If not set before, Issuer and Issuer Fingerprint subpackets are added
- /// pointing to `signer`.
+ ///
+ /// [`Signature`]: ../enum.Signature.html
+ ///
+ /// If neither an [`Issuer`] subpacket (set using
+ /// [`SignatureBuilder::set_issuer`], for instance) nor an
+ /// [`Issuer Fingerprint`] subpacket (set using
+ /// [`SignatureBuilder::set_issuer_fingerprint`], for instance) is
+ /// set, they are both added to the new `Signature`'s unhashed
+ /// subpacket area and set to the `signer`'s `KeyID` and
+ /// `Fingerprint`, respectively.
+ ///
+ /// [`Issuer`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.5
+ /// [`SignatureBuilder::set_issuer`]: #method.set_issuer
+ /// [`Issuer Fingerprint`]: https://www.ietf.org/id/draft-ietf-openpgp-rfc4880bis-09.html#section-5.2.3.28
+ /// [`SignatureBuilder::set_issuer_fingerprint`]: #method.set_issuer_fingerprint
+ ///
+ /// Likewise, a [`Signature Creation Time`] subpacket set to the
+ /// current time is added to the hashed area if the `Signature
+ /// Creation Time` subpacket hasn't been set using, for instance,
+ /// the [`set_signature_creation_time`] method or the
+ /// [`preserve_signature_creation_time`] method.
+ ///
+ /// [`Signature Creation Time`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.4
+ /// [`set_signature_creation_time`]: #method.set_signature_creation_time
+ /// [`preserve_signature_creation_time`]: #method.preserve_signature_creation_time
+ ///
+ /// # Examples
+ ///
+ /// Add a new subkey intended for encrypting data in motion to an
+ /// existing certificate:
+ ///
+ /// ```
+ /// use sequoia_openpgp as openpgp;
+ /// use openpgp::cert::prelude::*;
+ /// use openpgp::packet::prelude::*;
+ /// use openpgp::policy::StandardPolicy;
+ /// use openpgp::types::KeyFlags;
+ /// use openpgp::types::SignatureType;
+ ///
+ /// # fn main() -> openpgp::Result<()> {
+ /// let p = &StandardPolicy::new();
+ ///
+ /// let (cert, _) = CertBuilder::new().generate()?;
+ /// # assert_eq!(cert.keys().count(), 1);
+ ///
+ /// let pk = cert.primary_key().key().clone().parts_into_secret()?;
+ /// // Derive a signer.
+ /// let mut pk_signer = pk.clone().into_keypair()?;
+ ///
+ /// // Generate an encryption subkey.
+ /// let mut subkey: Key<_, _> = Key4::generate_rsa(3072)?.into();
+ /// // Derive a signer.
+ /// let mut sk_signer = subkey.clone().into_keypair()?;
+ ///
+ /// let sig = SignatureBuilder::new(SignatureType::SubkeyBinding)
+ /// .set_key_flags(&KeyFlags::empty().set_transport_encryption())?
+ /// .sign_subkey_binding(&mut pk_signer, &pk, &subkey)?;
+ ///
+ /// let cert = cert.merge_packets(vec![Packet::SecretSubkey(subkey),
+ /// sig.into()])?;
+ ///
+ /// assert_eq!(cert.with_policy(p, None)?.keys().count(), 2);
+ /// # Ok(())
+ /// # }
+ /// ```
pub fn sign_subkey_binding<P, Q>(mut self, signer: &mut dyn Signer,
primary: &Key<P, key::PrimaryRole>,
subkey: &Key<Q, key::SubordinateRole>)
-> Result<Signature>
- where P: key:: KeyParts,
- Q: key:: KeyParts,
+ where P: key::KeyParts,
+ Q: key::KeyParts,
{
match self.typ {
SignatureType::SubkeyBinding => (),
@@ -359,20 +821,140 @@ impl SignatureBuilder {
self.sign(signer, digest)
}
- /// Signs primary key binding from `primary` to `subkey` using
- /// `subkey_signer`.
+ /// Generates a primary key binding signature.
+ ///
+ /// A [primary key binding signature], also referred to as a back
+ /// signature or backsig, is a signature over the primary key and
+ /// a subkey, which is made by the subkey. This signature is a
+ /// statement by the subkey that it belongs to the primary key.
+ /// That is, it binds the certificate to the subkey. It is
+ /// normally stored in the subkey binding signature (see
+ /// [`SignatureBuilder::sign_subkey_binding`]) in the [`Embedded
+ /// Signature`] subpacket (set using
+ /// [`SignatureBuilder::set_embedded_signature`]).
+ ///
+ /// [primary key binding signature]: https://tools.ietf.org/html/rfc4880#section-5.2.1
+ /// [`SignatureBuilder::sign_subkey_binding`]: #method.sign_subkey_binding
+ /// [`Embedded Signature`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.26
+ /// [`SignatureBuilder::set_embedded_signature`]: #method.set_embedded_signature
+ ///
+ /// All subkeys that make signatures of any sort (signature
+ /// subkeys, certification subkeys, and authentication subkeys)
+ /// must include this signature in their binding signature. This
+ /// signature ensures that an attacker (Mallory) can't claim
+ /// someone else's (Alice's) signing key by just creating a subkey
+ /// binding signature. If that were the case, anyone who has
+ /// Mallory's certificate could be tricked into thinking that
+ /// Mallory made signatures that were actually made by Alice.
+ /// This signature prevents this attack, because it proves that
+ /// the person who controls the private key for the primary key
+ /// also controls the private key for the subkey and therefore
+ /// intended that the subkey be associated with the primary key.
+ /// Thus, although Mallory controls his own primary key and can
+ /// issue a subkey binding signature for Alice's signing key, he
+ /// doesn't control her signing key, and therefore can't create a
+ /// valid backsig.
+ ///
+ /// A primary key binding signature is not needed for
+ /// encryption-capable subkeys. This is firstly because
+ /// encryption-capable keys cannot make signatures. But also
+ /// because an attacker doesn't gain anything by adopting an
+ /// encryption-capable subkey: without the private key material,
+ /// they still can't read the message's content.
+ ///
+ /// This function checks that the [signature type] (passed to
+ /// [`SignatureBuilder::new`], set via
+ /// [`SignatureBuilder::set_type`], or copied when using
+ /// `SignatureBuilder::From`) is
+ /// [`SignatureType::PrimaryKeyBinding`], or
+ /// [`SignatureType::Unknown`].
+ ///
+ /// [signature type]: ../../types/enum.SignatureType.html
+ /// [`SignatureBuilder::new`]: #method.new
+ /// [`SignatureBuilder::set_type`]: #method.set_type
+ /// [`SignatureType::PrimaryKeyBinding`]: ../../types/enum.SignatureType.html#variant.PrimaryKeyBinding
+ /// [`SignatureType::Unknown`]: ../../types/enum.SignatureType.html#variant.Unknown
+ ///
+ /// The [`Signature`]'s public-key algorithm field is set to the
+ /// algorithm used by `signer`.
///
- /// The Signature's public-key algorithm field is set to the
- /// algorithm used by `subkey_signer`.
- /// If not set before, Issuer and Issuer Fingerprint subpackets are added
- /// pointing to `subkey_signer`.
+ /// [`Signature`]: ../enum.Signature.html
+ ///
+ /// If neither an [`Issuer`] subpacket (set using
+ /// [`SignatureBuilder::set_issuer`], for instance) nor an
+ /// [`Issuer Fingerprint`] subpacket (set using
+ /// [`SignatureBuilder::set_issuer_fingerprint`], for instance) is
+ /// set, they are both added to the new `Signature`'s unhashed
+ /// subpacket area and set to the `signer`'s `KeyID` and
+ /// `Fingerprint`, respectively.
+ ///
+ /// [`Issuer`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.5
+ /// [`SignatureBuilder::set_issuer`]: #method.set_issuer
+ /// [`Issuer Fingerprint`]: https://www.ietf.org/id/draft-ietf-openpgp-rfc4880bis-09.html#section-5.2.3.28
+ /// [`SignatureBuilder::set_issuer_fingerprint`]: #method.set_issuer_fingerprint
+ ///
+ /// Likewise, a [`Signature Creation Time`] subpacket set to the
+ /// current time is added to the hashed area if the `Signature
+ /// Creation Time` subpacket hasn't been set using, for instance,
+ /// the [`set_signature_creation_time`] method or the
+ /// [`preserve_signature_creation_time`] method.
+ ///
+ /// [`Signature Creation Time`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.4
+ /// [`set_signature_creation_time`]: #method.set_signature_creation_time
+ /// [`preserve_signature_creation_time`]: #method.preserve_signature_creation_time
+ ///
+ /// # Examples
+ ///
+ /// Add a new signing-capable subkey to an existing certificate.
+ /// Because we are adding a signing-capable subkey, the binding
+ /// signature needs to include a backsig.
+ ///
+ /// ```
+ /// use sequoia_openpgp as openpgp;
+ /// use openpgp::cert::prelude::*;
+ /// use openpgp::packet::prelude::*;
+ /// use openpgp::policy::StandardPolicy;
+ /// use openpgp::types::KeyFlags;