From 1fcdd57d93a1d365123ca9a897e5067f3bb6d273 Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Tue, 3 Dec 2024 20:32:09 +0100 Subject: [PATCH] Implement `sq pki vouch {add,authorize} --certifier-self`. - This selects the default certification key controlled by the `pki.vouch.certifier-self` setting. - See #336. --- src/cli/pki/vouch.rs | 3 ++ src/cli/pki/vouch/add.rs | 2 +- src/cli/pki/vouch/authorize.rs | 2 +- src/cli/types/cert_designator.rs | 24 +++++++++++ src/config.rs | 71 ++++++++++++++++++++++++++++++++ src/sq.rs | 37 +++++++++++------ 6 files changed, 125 insertions(+), 14 deletions(-) diff --git a/src/cli/pki/vouch.rs b/src/cli/pki/vouch.rs index 3de0e57e..6e95d503 100644 --- a/src/cli/pki/vouch.rs +++ b/src/cli/pki/vouch.rs @@ -7,6 +7,9 @@ use clap::{Parser, Subcommand}; use crate::cli::examples::*; +/// Key for the help augmentation. +pub const CERTIFIER_SELF: &str = "pki.vouch.certifier-self"; + #[derive(Parser, Debug)] #[clap( name = "vouch", diff --git a/src/cli/pki/vouch/add.rs b/src/cli/pki/vouch/add.rs index 202fcfce..445cb9a8 100644 --- a/src/cli/pki/vouch/add.rs +++ b/src/cli/pki/vouch/add.rs @@ -85,7 +85,7 @@ reference time. }))] pub struct Command { #[command(flatten)] - pub certifier: CertDesignators, diff --git a/src/cli/pki/vouch/authorize.rs b/src/cli/pki/vouch/authorize.rs index cc6ebc66..62bace40 100644 --- a/src/cli/pki/vouch/authorize.rs +++ b/src/cli/pki/vouch/authorize.rs @@ -96,7 +96,7 @@ reference time. }))] pub struct Command { #[command(flatten)] - pub certifier: CertDesignators, diff --git a/src/cli/types/cert_designator.rs b/src/cli/types/cert_designator.rs index 3efa7471..8df2c90c 100644 --- a/src/cli/types/cert_designator.rs +++ b/src/cli/types/cert_designator.rs @@ -14,6 +14,7 @@ use openpgp::packet::UserID; use crate::cli::config; use crate::cli::encrypt::ENCRYPT_FOR_SELF; use crate::cli::sign::SIGNER_SELF; +use crate::cli::pki::vouch::CERTIFIER_SELF; use crate::cli::types::SpecialName; /// The prefix for the designators. @@ -771,6 +772,29 @@ This adds the certificates listed in the configuration file under \ }), ), + "certifier" => ( + "Create the certification using your default certification \ + key", + format!( +"Create the certification using your default certification key + +This uses the certificates set in the configuration file under \ +`{}` as certification key. + +{} +", + CERTIFIER_SELF, + if let Some(cert) + = config::get_augmentation(CERTIFIER_SELF) + { + format!("The following key will be used: {}.", + cert) + } else { + "Currently, there is no default certification key." + .into() + }), + ), + #[cfg(test)] "cert" => ( "dummy text for the test", diff --git a/src/config.rs b/src/config.rs index 9b2c2d87..3d8447f4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -54,6 +54,10 @@ pub struct Config { /// The set of signing keys selected using `--signer-self`. sign_signer_self: BTreeSet, + /// The default certification key selected using + /// `--certifier-self`. + pki_vouch_certifier_self: Option, + policy_path: Option, policy_inline: Option>, cipher_suite: Option, @@ -82,6 +86,7 @@ impl Default for Config { hints: None, encrypt_for_self: Default::default(), sign_signer_self: Default::default(), + pki_vouch_certifier_self: None, policy_path: None, policy_inline: None, cipher_suite: None, @@ -168,6 +173,12 @@ impl Config { &self.sign_signer_self } + /// Returns the key that should be used as certifier if + /// `--certifier-self` is given. + pub fn pki_vouch_certifier_self(&self) -> &Option { + &self.pki_vouch_certifier_self + } + /// Returns the path to the referenced cryptographic policy, if /// any. pub fn policy_path(&self) -> Option<&Path> { @@ -289,6 +300,9 @@ impl ConfigFile { [sign] #signer-self = [\"fingerprint of your key\"] +[pki.vouch] +#certifier-self = \"fingerprint of your key\" + [key.generate] #cipher-suite = @@ -704,6 +718,7 @@ const TOP_LEVEL_SCHEMA: Schema = &[ ("encrypt", apply_encrypt), ("key", apply_key), ("network", apply_network), + ("pki", apply_pki), ("policy", apply_policy), ("servers", apply_servers), ("sign", apply_sign), @@ -877,6 +892,62 @@ fn apply_sign_signer_self(config: &mut Option<&mut Config>, Ok(()) } +/// Schema for the `pki` section. +const PKI_SCHEMA: Schema = &[ + ("vouch", apply_pki_vouch), +]; + +/// Validates the `pki` section. +fn apply_pki(config: &mut Option<&mut Config>, + cli: &mut Option<&mut Augmentations>, + path: &str, item: &Item) + -> Result<()> +{ + let section = item.as_table_like() + .ok_or_else(|| Error::bad_item_type(path, item, "table"))?; + apply_schema(config, cli, Some(path), section.iter(), PKI_SCHEMA)?; + Ok(()) +} + +/// Schema for the `pki.vouch` section. +const PKI_VOUCH_SCHEMA: Schema = &[ + ("certifier-self", apply_pki_vouch_certifier_self), +]; + +/// Validates the `pki.vouch` section. +fn apply_pki_vouch(config: &mut Option<&mut Config>, + cli: &mut Option<&mut Augmentations>, + path: &str, item: &Item) + -> Result<()> +{ + let section = item.as_table_like() + .ok_or_else(|| Error::bad_item_type(path, item, "table"))?; + apply_schema(config, cli, Some(path), section.iter(), PKI_VOUCH_SCHEMA)?; + Ok(()) +} + +/// Validates the `pki.vouch.certifier-self` value. +fn apply_pki_vouch_certifier_self(config: &mut Option<&mut Config>, + cli: &mut Option<&mut Augmentations>, + path: &str, item: &Item) + -> Result<()> +{ + let s = item.as_str() + .ok_or_else(|| Error::bad_item_type(path, item, "string"))?; + + let fp = s.parse::()?; + + if let Some(cli) = cli { + cli.insert("pki.vouch.certifier-self", fp.to_string()); + } + + if let Some(config) = config { + config.pki_vouch_certifier_self = Some(fp); + } + + Ok(()) +} + /// Schema for the `key` section. const KEY_SCHEMA: Schema = &[ ("generate", apply_key_generate), diff --git a/src/sq.rs b/src/sq.rs index 1538d22e..16329bd5 100644 --- a/src/sq.rs +++ b/src/sq.rs @@ -2105,28 +2105,41 @@ impl<'store: 'rstore, 'rstore> Sq<'store, 'rstore> { }, cert_designator::CertDesignator::Self_ => { - let (certs, config) = match Prefix::name() { - "for" => (self.config.encrypt_for_self(), - cli::encrypt::ENCRYPT_FOR_SELF), - "signer" => (self.config.sign_signer_self(), - cli::sign::SIGNER_SELF), + let (certs, config): (Box>, _) + = match Prefix::name() + { + "for" => ( + Box::new(self.config.encrypt_for_self().iter()), + cli::encrypt::ENCRYPT_FOR_SELF, + ), + "signer" => ( + Box::new(self.config.sign_signer_self().iter()), + cli::sign::SIGNER_SELF, + ), + "certifier" => ( + Box::new(self.config.pki_vouch_certifier_self().iter()), + cli::pki::vouch::CERTIFIER_SELF, + ), _ => return Err(anyhow::anyhow!( "self designator used with unexpected prefix")), }; - if certs.is_empty() { - return Err(anyhow::anyhow!( - "`--for-self` is given but the list of \ - certificates in `{}` is empty", - config)); - } - + let mut one = false; for fp in certs { let cert = self.resolve_cert( &openpgp::KeyHandle::from(fp.clone()).into(), 0)?.0; ret(designator, Ok(Arc::new(cert.into())), true, true); + one = true; + } + + if ! one { + return Err(anyhow::anyhow!( + "`--{}-self` is given but no default \ + is set in the configuration file under `{}`", + Prefix::name(), + config)); } }, }