diff options
author | Neal H. Walfield <neal@pep.foundation> | 2020-08-07 23:42:51 +0200 |
---|---|---|
committer | Neal H. Walfield <neal@pep.foundation> | 2020-08-12 09:25:07 +0200 |
commit | 9a5f5b44335240daac54fa8eb9efa2a8fff9fd27 (patch) | |
tree | c97414c25274e2283c5e4ad5d1d0e5bdbb4ba211 | |
parent | a0b4afd578e1cd76aa2d82bdf7d53d20d9ec6965 (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.rs | 889 |
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; |