Implement sq pki vouch {add,authorize} --certifier-self.

- This selects the default certification key controlled by the
    `pki.vouch.certifier-self` setting.

  - See #336.
This commit is contained in:
Justus Winter 2024-12-03 20:32:09 +01:00
parent 0d37335aad
commit 1fcdd57d93
No known key found for this signature in database
GPG Key ID: 686F55B4AB2B3386
6 changed files with 125 additions and 14 deletions

View File

@ -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",

View File

@ -85,7 +85,7 @@ reference time.
}))]
pub struct Command {
#[command(flatten)]
pub certifier: CertDesignators<CertUserIDEmailFileArgs,
pub certifier: CertDesignators<CertUserIDEmailFileSelfArgs,
CertifierPrefix,
OneValue,
CertifierDoc>,

View File

@ -96,7 +96,7 @@ reference time.
}))]
pub struct Command {
#[command(flatten)]
pub certifier: CertDesignators<CertUserIDEmailFileArgs,
pub certifier: CertDesignators<CertUserIDEmailFileSelfArgs,
CertifierPrefix,
OneValue,
CertifierDoc>,

View File

@ -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",

View File

@ -54,6 +54,10 @@ pub struct Config {
/// The set of signing keys selected using `--signer-self`.
sign_signer_self: BTreeSet<Fingerprint>,
/// The default certification key selected using
/// `--certifier-self`.
pki_vouch_certifier_self: Option<Fingerprint>,
policy_path: Option<PathBuf>,
policy_inline: Option<Vec<u8>>,
cipher_suite: Option<sequoia_openpgp::cert::CipherSuite>,
@ -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<Fingerprint> {
&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 = <DEFAULT-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::<Fingerprint>()?;
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),

View File

@ -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<dyn Iterator<Item=&Fingerprint>>, _)
= 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));
}
},
}