Use cert designators for sq key userid revoke.

- See #207.
This commit is contained in:
Justus Winter 2024-10-23 17:53:32 +02:00
parent 31ca4e2943
commit 77d9edf039
No known key found for this signature in database
GPG Key ID: 686F55B4AB2B3386
3 changed files with 53 additions and 77 deletions

2
NEWS
View File

@ -126,6 +126,8 @@
- The argument `sq key revoke --file` now requires `--output`.
- The argument `sq key userid add --cert-file` now requires
`--output`.
- The argument `sq key userid revoke --cert-file` now requires
`--output`.
* Changes in 0.38.0
** Notable changes

View File

@ -1,13 +1,11 @@
use clap::{ValueEnum, ArgGroup, Args, Subcommand};
use sequoia_openpgp as openpgp;
use openpgp::KeyHandle;
use openpgp::packet::UserID;
use openpgp::types::ReasonForRevocation;
use crate::cli::types::ClapData;
use crate::cli::types::FileOrCertStore;
use crate::cli::types::FileOrStdin;
use crate::cli::types::FileOrStdout;
use crate::cli::types::cert_designator::*;
@ -145,7 +143,7 @@ modified certificate to stdout.",
pub binary: bool,
}
/// Documentation for the cert designators for the key expire.
/// Documentation for the cert designators for the key userid add.
pub struct UserIDAddDoc {}
impl AdditionalDocs for UserIDAddDoc {
@ -208,59 +206,18 @@ instead of the current time.
",
after_help = USERID_REVOKE_EXAMPLES,
)]
#[clap(group(ArgGroup::new("cert_input").args(&["cert_file", "cert"]).required(true)))]
#[clap(group(ArgGroup::new("revoker_input").args(&["revoker_file", "revoker"])))]
#[clap(group(ArgGroup::new("cert-userid").args(&["name", "email", "userid"]).required(true)))]
pub struct RevokeCommand {
#[clap(
long,
value_name = "FINGERPRINT|KEYID",
help = "Revoke the user ID on the specified certificate",
)]
pub cert: Option<KeyHandle>,
#[clap(
long,
help = FileOrStdin::HELP_OPTIONAL,
value_name = "CERT_FILE",
conflicts_with = "cert",
help = "Revoke the user ID on the specified certificate",
long_help = "\
Revoke the user ID on the specified certificate.
#[command(flatten)]
pub cert: CertDesignators<CertUserIDEmailFileArgs,
CertPrefix,
OneValueAndFileRequiresOutput,
UserIDRevokeCertDoc>,
Read the certificate whose user ID should be revoked from FILE or \
stdin, if `-`. It is an error for the file to contain more than one \
certificate.",
)]
pub cert_file: Option<FileOrStdin>,
#[clap(
long,
value_name = "FINGERPRINT|KEYID",
help = "The certificate that issues the revocation",
long_help = "\
The certificate that issues the revocation.
Sign the revocation certificate using the specified key. By default, \
the certificate being revoked is used. Using this option, it is \
possible to create a third-party revocation.",
)]
pub revoker: Option<KeyHandle>,
#[clap(
long,
value_name = "KEY_FILE",
conflicts_with = "revoker",
help = "The certificate that issues the revocation",
long_help = "\
The certificate that issues the revocation.
Sign the revocation certificate using the specified key. By default, \
the certificate being revoked is used. Using this option, it is \
possible to create a third-party revocation.
Read the certificate from KEY_FILE or stdin, if `-`. It is an error \
for the file to contain more than one certificate.",
)]
pub revoker_file: Option<FileOrStdin>,
#[command(flatten)]
pub revoker: CertDesignators<CertUserIDEmailFileArgs,
RevokerPrefix,
OneOptionalValue,
UserIDRevokeRevokerDoc>,
#[clap(
long = "name",
@ -368,6 +325,40 @@ modified certificate to stdout.",
pub binary: bool,
}
/// Documentation for the cert designators for the key userid revoke.
pub struct UserIDRevokeCertDoc {}
impl AdditionalDocs for UserIDRevokeCertDoc {
fn help(arg: &'static str, help: &'static str) -> clap::builder::StyledStr {
match arg {
"file" =>
"Revoke the user ID from the key \
read from PATH"
.into(),
_ => {
debug_assert!(help.starts_with("Use certificates"));
help.replace("Use certificates",
"Revoke the user ID from the key")
.into()
},
}
}
}
/// Documentation for the revoker designators for the key userid revoke revoker.
pub struct UserIDRevokeRevokerDoc {}
impl AdditionalDocs for UserIDRevokeRevokerDoc {
fn help(_: &'static str, help: &'static str) -> clap::builder::StyledStr {
format!("{} to create the revocation certificate.
Sign the revocation certificate using the specified key. By default, \
the certificate being revoked is used. Using this option, it is \
possible to create a third-party revocation.",
help.replace("certificates", "key")).into()
}
}
/// The revocation reason for a user ID
#[derive(ValueEnum, Clone, Debug)]
pub enum UserIDReasonForRevocation {

View File

@ -13,7 +13,6 @@ use openpgp::packet::signature::subpacket::NotationData;
use openpgp::packet::signature::subpacket::SubpacketTag;
use openpgp::packet::signature::SignatureBuilder;
use openpgp::packet::UserID;
use openpgp::parse::Parse;
use openpgp::policy::HashAlgoSecurity;
use openpgp::policy::Policy;
use openpgp::serialize::Serialize;
@ -29,7 +28,6 @@ use cert_store::StoreUpdate;
use crate::Sq;
use crate::cli;
use crate::cli::key::userid::RevokeCommand;
use crate::cli::types::FileOrStdout;
use crate::common::NULL_POLICY;
use crate::common::RevocationOutput;
use crate::common::get_secret_signer;
@ -342,22 +340,10 @@ fn userid_add(
/// [`NotationData`] fails or if the eventual revocation fails.
pub fn userid_revoke(
sq: Sq,
mut command: RevokeCommand,
command: RevokeCommand,
) -> Result<()> {
let cert = if let Some(file) = command.cert_file {
if command.output.is_none() {
// None means to write to the cert store. When reading
// from a file, we want to write to stdout by default.
command.output = Some(FileOrStdout::new(None));
}
let br = file.open()?;
Cert::from_buffered_reader(br)?
} else if let Some(kh) = command.cert {
sq.lookup_one(&kh, None, true)?
} else {
panic!("clap enforces --cert or --cert-file");
};
let cert =
sq.resolve_cert(&command.cert, sequoia_wot::FULLY_TRUSTED)?.0;
let userid = if let Some(n) = command.name {
lint_name(&n)?;
@ -369,13 +355,10 @@ pub fn userid_revoke(
UserID::from(command.userid.expect("one of the three must be given"))
};
let revoker = if let Some(file) = command.revoker_file {
let br = file.open()?;
Some(Cert::from_buffered_reader(br)?)
} else if let Some(kh) = command.revoker {
Some(sq.lookup_one(&kh, None, true)?)
} else {
let revoker = if command.revoker.is_empty() {
None
} else {
Some(sq.resolve_cert(&command.revoker, sequoia_wot::FULLY_TRUSTED)?.0)
};
let notations = parse_notations(command.notation)?;