diff options
author | Neal H. Walfield <neal@sequoia-pgp.org> | 2024-01-23 09:08:04 +0100 |
---|---|---|
committer | Neal H. Walfield <neal@sequoia-pgp.org> | 2024-01-23 11:14:04 +0100 |
commit | 7c5efa151eb99429401f871792090c0c5cf9f63e (patch) | |
tree | 2d04a7778e0584f8ca5ce4ef1e1b78fea0549925 /openpgp | |
parent | 4865e156d34a3e5604e1e2dbb42468151e30725a (diff) |
openpgp: Add a method to CertBuilder to make non-exportable certs.
- Add `CertBuilder::set_exportable`, which sets the exportable flag
accordingly on all generated signatures.
- This allows the easy creation of non-exportable certificates,
which is recommended by the OpenPGP Certificate Directory
specification for the local trust root:
> The trust root is an OpenPGP certificate that is stored under
> the special name trust-root.
>
> The certificate:
>
> SHOULD use direct key signatures or binding signatures that are marked as non-exportable.
https://www.ietf.org/archive/id/draft-nwjw-openpgp-cert-d-00.html#section-3.5.1
- Fixes #1082.
Diffstat (limited to 'openpgp')
-rw-r--r-- | openpgp/NEWS | 1 | ||||
-rw-r--r-- | openpgp/src/cert/builder.rs | 37 |
2 files changed, 31 insertions, 7 deletions
diff --git a/openpgp/NEWS b/openpgp/NEWS index 1aac12d3..1ce386c5 100644 --- a/openpgp/NEWS +++ b/openpgp/NEWS @@ -14,6 +14,7 @@ - KeyAmalgamation::valid_third_party_revocations_by_key - Parse::from_buffered_reader - armor::Reader::from_buffered_reader + - CertBuilder::set_exportable * Changes in 1.17.0 ** Notable fixes - Sequoia now ignores some formatting errors when reading secret diff --git a/openpgp/src/cert/builder.rs b/openpgp/src/cert/builder.rs index 82045295..db864ed0 100644 --- a/openpgp/src/cert/builder.rs +++ b/openpgp/src/cert/builder.rs @@ -275,6 +275,7 @@ pub struct CertBuilder<'a> { user_attributes: Vec<(Option<SignatureBuilder>, packet::UserAttribute)>, password: Option<Password>, revocation_keys: Option<Vec<RevocationKey>>, + exportable: bool, phantom: PhantomData<&'a ()>, } assert_send_and_sync!(CertBuilder<'_>); @@ -331,6 +332,7 @@ impl CertBuilder<'_> { user_attributes: vec![], password: None, revocation_keys: None, + exportable: true, phantom: PhantomData, } } @@ -507,6 +509,18 @@ impl CertBuilder<'_> { self } + /// Sets whether the certificate is exportable. + /// + /// This method controls whether the certificate is exportable. + /// If the certificate builder is configured to make a + /// non-exportable certificate, then all of the signatures that it + /// creates include the an [Exportable Certification] subpacket + /// that is set to `false`. + pub fn set_exportable(mut self, exportable: bool) -> Self { + self.exportable = exportable; + self + } + /// Adds a User ID. /// /// Adds a User ID to the certificate. The first User ID that is @@ -1387,7 +1401,8 @@ impl CertBuilder<'_> { for (template, uid) in self.userids.into_iter() { let sig = template.unwrap_or_else( || SignatureBuilder::new(SignatureType::PositiveCertification)); - let sig = Self::signature_common(sig, creation_time)?; + let sig = Self::signature_common(sig, creation_time, + self.exportable)?; let mut sig = Self::add_primary_key_metadata(sig, &self.primary)?; // Make sure we mark exactly one User ID or Attribute as @@ -1417,7 +1432,8 @@ impl CertBuilder<'_> { for (template, ua) in self.user_attributes.into_iter() { let sig = template.unwrap_or_else( || SignatureBuilder::new(SignatureType::PositiveCertification)); - let sig = Self::signature_common(sig, creation_time)?; + let sig = Self::signature_common( + sig, creation_time, self.exportable)?; let mut sig = Self::add_primary_key_metadata(sig, &self.primary)?; // Make sure we mark exactly one User ID or Attribute as @@ -1453,7 +1469,8 @@ impl CertBuilder<'_> { let sig = template.unwrap_or_else( || SignatureBuilder::new(SignatureType::SubkeyBinding)); - let sig = Self::signature_common(sig, creation_time)?; + let sig = Self::signature_common( + sig, creation_time, self.exportable)?; let mut builder = sig .set_key_flags(flags.clone())? .set_key_validity_period(blueprint.validity.or(self.primary.validity))?; @@ -1507,7 +1524,8 @@ impl CertBuilder<'_> { .generate_key(KeyFlags::empty().set_certification())?; key.set_creation_time(creation_time)?; let sig = SignatureBuilder::new(SignatureType::DirectKey); - let sig = Self::signature_common(sig, creation_time)?; + let sig = Self::signature_common( + sig, creation_time, self.exportable)?; let mut sig = Self::add_primary_key_metadata(sig, &self.primary)?; if let Some(ref revocation_keys) = self.revocation_keys { @@ -1523,13 +1541,18 @@ impl CertBuilder<'_> { /// Common settings for generated signatures. fn signature_common(builder: SignatureBuilder, - creation_time: time::SystemTime) + creation_time: time::SystemTime, + exportable: bool) -> Result<SignatureBuilder> { - builder + let mut builder = builder // GnuPG wants at least a 512-bit hash for P521 keys. .set_hash_algo(HashAlgorithm::SHA512) - .set_signature_creation_time(creation_time) + .set_signature_creation_time(creation_time)?; + if ! exportable { + builder = builder.set_exportable_certification(false)?; + } + Ok(builder) } |