use anyhow::{Context, Result}; use sequoia_openpgp::{ cert::CertBuilder, packet::{signature::SignatureBuilder, Signature}, types::{KeyFlags, SignatureType}, Cert, }; use spec::{KeyFlag, Spec}; mod paths; mod setup; mod spec; fn main() -> Result<()> { let (paths, spec) = crate::setup::setup().context("Failed to setup application")?; let (cert, rev) = paths.load()?.ok_or(()).or_else(|()| generate_new(spec))?; paths .write(cert, rev) .context("Failed to store certificate!")?; Ok(()) } fn generate_new(spec: Spec) -> Result<(Cert, Signature)> { let mut builder = CertBuilder::new() .set_primary_key_flags( spec.primary .flags .iter() .fold(KeyFlags::empty(), KeyFlag::fold), ) .set_validity_period( spec.primary .expiry .validity_period .or(spec.expiry.validity_period), ) .set_cipher_suite(spec.primary.cipher_suite); for sub_key in spec.subs { builder = builder.add_subkey_with( sub_key.flags.iter().fold(KeyFlags::empty(), KeyFlag::fold), sub_key .expiry .validity_period .or(spec.expiry.validity_period), Some(sub_key.cipher_suite), SignatureBuilder::new(SignatureType::SubkeyBinding), )?; } for user_id in spec.user_ids { let mut sig_builder = SignatureBuilder::new(SignatureType::PositiveCertification); for (key, value) in user_id.notation { sig_builder = sig_builder .add_notation(key, value, None, false) .context(format!( "Failed to add notation to signature builder for {}", &user_id.value ))?; } builder = builder .add_userid_with(user_id.value.clone(), sig_builder) .context(format!( "Failed to add user ID {} to certificate builder", &user_id.value ))?; } builder .generate() .context("Failed to generate certificate!") }