diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2020-12-09 17:09:47 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2021-04-12 18:07:08 +0200 |
commit | 6a26439ee4c5b780d7f507d3bbb44c4f1dd0cc97 (patch) | |
tree | 33c255ff52b5b0c7d0410b4fe6790556c3554489 | |
parent | 4aa2c1826a4c8c077dd03becb072496660cf7c00 (diff) |
openpgp: Add example that creates a group key.
-rw-r--r-- | openpgp/examples/generate-group-key.rs | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/openpgp/examples/generate-group-key.rs b/openpgp/examples/generate-group-key.rs new file mode 100644 index 00000000..6dee235a --- /dev/null +++ b/openpgp/examples/generate-group-key.rs @@ -0,0 +1,102 @@ +//! Illustrates how to create keys and certificates for group +//! conversations. +//! +//! This example, when run, generates four artifacts: +//! +//! ```text +//! % cargo run -p sequoia-openpgp --example generate-group-key cabal@example.org +//! [...] +//! Writing certificate to cabal@example.org.cert.pgp +//! Writing full key to cabal@example.org.key.pgp +//! Writing key with detached primary to cabal@example.org.only_subkey.pgp +//! Writing revocation certificate to cabal@example.org.revocation.pgp +//! ``` +//! +//! - If you want to receive unsolicited encrypted messages on the +//! address (e.g. in case of a security contact or a public mailing +//! list), you should publish this in a suitable way, e.g. using +//! WKD. Consider authenticating this certificate using OpenPGP-CA. +//! +//! - Distribute the certificate freely if you want to receive +//! unsolicited encrypted messages. +//! +//! - Distribute the key with the detached primary among the group, +//! for example by including it in an email encrypted to all +//! members. +//! +//! - Make a backup of full key and revocation certificate. +//! +//! - Consider distributing the revocation certificate among a select, +//! trusted group that can help when disaster strikes. The security +//! implication of handing out the revocation certificate is a +//! denial-of-service vector. + +use std::fs::File; +use std::time::Duration; + +use sequoia_openpgp as openpgp; +use openpgp::armor; +use openpgp::cert::prelude::*; +use openpgp::types::KeyFlags; +use openpgp::serialize::Serialize; + +fn main() -> openpgp::Result<()> { + let args: Vec<String> = std::env::args().collect(); + let name = if let Some(n) = args.get(1).cloned() { + n + } else { + return Err(anyhow::anyhow!( + "Missing list address parameter.\n\n\ + Usage: {} <LIST-ADDRESS>", + args.get(0).cloned().unwrap_or("generate-group-key".into()))); + }; + + // Generate the key. + let (cert, revocation) = CertBuilder::new() + .set_validity_period(Duration::new(5 * 365 * 24 * 60 * 60, 0)) + .add_userid(format!("<{}>", name)) + .add_subkey(KeyFlags::empty() + .set_transport_encryption() + .set_group_key(), + None, + None) + .generate()?; + + // First, emit the certificate. + let n = format!("{}.cert.pgp", name); + eprintln!("Writing certificate to {}", n); + cert.armored().serialize(&mut File::create(n)?)?; + + // Second, emit the key. This includes all secret key material. + // Back this up. + let n = format!("{}.key.pgp", name); + eprintln!("Writing full key to {}", n); + cert.as_tsk().armored().serialize(&mut File::create(n)?)?; + + // Third, emit they key, but only include the encryption subkey's + // secret key material. + let n = format!("{}.only_subkey.pgp", name); + eprintln!("Writing key with detached primary to {}", n); + cert.as_tsk() + .set_filter(|k| k.fingerprint() != cert.fingerprint()) + .emit_secret_key_stubs(true) // Enable GnuPG-style. + .armored() + .serialize(&mut File::create(n)?)?; + + // Finally, emit a revocation certificate. Back this up. + let n = format!("{}.revocation.pgp", name); + eprintln!("Writing revocation certificate to {}", n); + + // Be fancy and include comments in the revocation cert. + let mut comments = cert.armor_headers(); + comments.insert(0, "Revocation certificate for the following key:".into()); + comments.insert(1, "".into()); + let mut w = armor::Writer::with_headers( + File::create(n)?, + armor::Kind::PublicKey, + comments.iter().map(|c| ("Comment", c)))?; + openpgp::Packet::from(revocation).serialize(&mut w)?; + w.finalize()?; + + Ok(()) +} |