summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@sequoia-pgp.org>2024-01-23 09:08:04 +0100
committerNeal H. Walfield <neal@sequoia-pgp.org>2024-01-23 11:14:04 +0100
commit7c5efa151eb99429401f871792090c0c5cf9f63e (patch)
tree2d04a7778e0584f8ca5ce4ef1e1b78fea0549925
parent4865e156d34a3e5604e1e2dbb42468151e30725a (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.
-rw-r--r--openpgp/NEWS1
-rw-r--r--openpgp/src/cert/builder.rs37
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)
}