summaryrefslogtreecommitdiffstats
path: root/sq
diff options
context:
space:
mode:
authorNora Widdecke <nora@sequoia-pgp.org>2022-06-03 08:52:00 +0200
committerNora Widdecke <nora@sequoia-pgp.org>2022-06-08 14:49:43 +0200
commit207d4ba7b7fe9844ddc54c8962a4ce0c7f6fb0ba (patch)
tree139056a04654372c7df3ba14a587c61a428c9788 /sq
parent09cb68ffcd7ea7943d5aa55ce2e20618c3daeb40 (diff)
sq: Derive revoke subcommand.
- The changes in sq_usage.rs are formatting fixes. I avoided the additional effort of preserving formatting issues for the sake of exact equivalence. - This is part of the effort of moving to clap3's derive API and profit from the added type safety.
Diffstat (limited to 'sq')
-rw-r--r--sq/src/sq-usage.rs63
-rw-r--r--sq/src/sq_cli.rs833
2 files changed, 475 insertions, 421 deletions
diff --git a/sq/src/sq-usage.rs b/sq/src/sq-usage.rs
index e80dcde5..96e63f09 100644
--- a/sq/src/sq-usage.rs
+++ b/sq/src/sq-usage.rs
@@ -1653,7 +1653,6 @@
//! ### Subcommand revoke certificate
//!
//! ```text
-//!
//! Revokes a certificate
//!
//! Creates a revocation certificate for the certificate.
@@ -1734,21 +1733,17 @@
//! Print help information
//!
//! --notation <NAME> <VALUE>
-//!
//! Adds a notation to the certification. A user-defined notation's
-//! name
-//! must be of the form "name@a.domain.you.control.org". If the
+//! name must be of the form "name@a.domain.you.control.org". If the
//! notation's name starts with a !, then the notation is marked as
-//! being
-//! critical. If a consumer of a signature doesn't understand a
-//! critical
-//! notation, then it will ignore the signature. The notation is marked
-//! as being human readable.
+//! being critical. If a consumer of a signature doesn't understand a
+//! critical notation, then it will ignore the signature. The notation
+//! is marked as being human readable.
//!
//! --private-key-store <KEY_STORE>
//! Provides parameters for private key store
//!
-//! --revocation-key <FILE>
+//! --revocation-key <KEY>
//!
//! Signs the revocation certificate using KEY. If the key is different
//! from the certificate, this creates a third-party revocation. If
@@ -1758,7 +1753,6 @@
//! then that key is used to sign the revocation certificate.
//!
//! -t, --time <TIME>
-//!
//! Chooses keys valid at the specified time and sets the revocation
//! certificate's creation time
//! ```
@@ -1766,7 +1760,6 @@
//! ### Subcommand revoke subkey
//!
//! ```text
-//!
//! Revokes a subkey
//!
//! Creates a revocation certificate for a subkey.
@@ -1785,7 +1778,6 @@
//!
//! ARGS:
//! <SUBKEY>
-//!
//! The subkey to revoke. This must either be the subkey's Key ID or
//! its
//! fingerprint.
@@ -1836,15 +1828,14 @@
//! instance, if Alice has created a new key, she would generate a
//! 'superseded' revocation certificate for her old key, and might
//! include
-//! the message "I've created a new subkey, please refresh the
-//! certificate."
+//! the message "I've created a new subkey, please use
+//! that in the future."
//!
//! OPTIONS:
//! -B, --binary
//! Emits binary data
//!
//! --certificate <FILE>
-//!
//! Reads the certificate containing the subkey to revoke from FILE or
//! stdin,
//! if omitted. It is an error for the file to contain more than one
@@ -1854,21 +1845,17 @@
//! Print help information
//!
//! --notation <NAME> <VALUE>
-//!
//! Adds a notation to the certification. A user-defined notation's
-//! name
-//! must be of the form "name@a.domain.you.control.org". If the
+//! name must be of the form "name@a.domain.you.control.org". If the
//! notation's name starts with a !, then the notation is marked as
-//! being
-//! critical. If a consumer of a signature doesn't understand a
-//! critical
-//! notation, then it will ignore the signature. The notation is marked
-//! as being human readable.
+//! being critical. If a consumer of a signature doesn't understand a
+//! critical notation, then it will ignore the signature. The notation
+//! is marked as being human readable.
//!
//! --private-key-store <KEY_STORE>
//! Provides parameters for private key store
//!
-//! --revocation-key <FILE>
+//! --revocation-key <KEY>
//!
//! Signs the revocation certificate using KEY. If the key is different
//! from the certificate, this creates a third-party revocation. If
@@ -1878,7 +1865,6 @@
//! then that key is used to sign the revocation certificate.
//!
//! -t, --time <TIME>
-//!
//! Chooses keys valid at the specified time and sets the revocation
//! certificate's creation time
//! ```
@@ -1905,15 +1891,12 @@
//!
//! ARGS:
//! <USERID>
-//!
-//!
//! The User ID to revoke. By default, this must exactly match a
//! self-signed User ID. Use --force to generate a revocation
//! certificate
//! for a User ID, which is not self signed.
//!
//! <REASON>
-//!
//! The reason for the revocation. This must be either: retired, or
//! unspecified:
//!
@@ -1951,30 +1934,25 @@
//! Emits binary data
//!
//! --certificate <FILE>
-//!
-//! Reads the certificate to revoke from FILE or stdin, if omitted. It
-//! is
-//! an error for the file to contain more than one certificate.
+//! Reads the certificate to revoke from FILE or stdin,
+//! if omitted. It is an error for the file to contain more than one
+//! certificate.
//!
//! -h, --help
//! Print help information
//!
//! --notation <NAME> <VALUE>
-//!
//! Adds a notation to the certification. A user-defined notation's
-//! name
-//! must be of the form "name@a.domain.you.control.org". If the
+//! name must be of the form "name@a.domain.you.control.org". If the
//! notation's name starts with a !, then the notation is marked as
-//! being
-//! critical. If a consumer of a signature doesn't understand a
-//! critical
-//! notation, then it will ignore the signature. The notation is marked
-//! as being human readable.
+//! being critical. If a consumer of a signature doesn't understand a
+//! critical notation, then it will ignore the signature. The notation
+//! is marked as being human readable.
//!
//! --private-key-store <KEY_STORE>
//! Provides parameters for private key store
//!
-//! --revocation-key <FILE>
+//! --revocation-key <KEY>
//!
//! Signs the revocation certificate using KEY. If the key is different
//! from the certificate, this creates a third-party revocation. If
@@ -1984,7 +1962,6 @@
//! then that key is used to sign the revocation certificate.
//!
//! -t, --time <TIME>
-//!
//! Chooses keys valid at the specified time and sets the revocation
//! certificate's creation time
//! ```
diff --git a/sq/src/sq_cli.rs b/sq/src/sq_cli.rs
index 53a28816..b1e81529 100644
--- a/sq/src/sq_cli.rs
+++ b/sq/src/sq_cli.rs
@@ -1132,383 +1132,6 @@ $ sq packet join juliet.pgp-[0-3]*
.arg(Arg::new("binary")
.short('B').long("binary")
.help("Emits binary data")))
- )
- .subcommand(Command::new("revoke")
- .display_order(700)
- .about("Generates revocation certificates")
- .long_about(
- "
-Generates revocation certificates.
-
-A revocation certificate indicates that a certificate, a subkey, a
-User ID, or a signature should not be used anymore.
-
-A revocation certificate includes two fields, a type and a
-human-readable explanation, which allows the issuer to indicate why
-the revocation certificate was issued. It is important to set the
-type field accurately as this allows an OpenPGP implementation to
-better reason about artifacts whose validity relies on the revoked
-object. For instance, if a certificate is retired, it is reasonable
-to consider signatures that it made prior to its retirement as still
-being valid. However, if a certificate's secret key material is
-compromised, any signatures that it made should be considered
-potentially forged, as they could have been made by an attacker and
-backdated.
-
-As the intent of a revocation certificate is to stop others from using
-a certificate, it is necessary to distribute the revocation
-certificate. One effective way to do this is to upload the revocation
-certificate to a keyserver.
-")
- .after_help(
-"EXAMPLES:
-
-# Revoke a certificate.
-$ sq revoke certificate --time 20220101 --certificate juliet.pgp \\
- compromised \"My parents went through my things, and found my backup.\"
-
-# Revoke a User ID.
-$ sq revoke userid --time 20220101 --certificate juliet.pgp \\
- \"Juliet <juliet@capuleti.it>\" retired \"I've left the family.\"
-")
- .subcommand_required(true)
- .arg_required_else_help(true)
- .subcommand(Command::new("certificate")
- .display_order(100)
- .about("Revoke a certificate")
- .long_about("
-Revokes a certificate
-
-Creates a revocation certificate for the certificate.
-
-If \"--revocation-key\" is provided, then that key is used to create
-the signature. If that key is different from the certificate being
-revoked, this creates a third-party revocation. This is normally only
-useful if the owner of the certificate designated the key to be a
-designated revoker.
-
-If \"--revocation-key\" is not provided, then the certificate must
-include a certification-capable key.")
-
- .arg(Arg::new("input")
- .value_name("FILE")
- .long("certificate")
- .alias("cert")
- .help("The certificate to revoke")
- .long_help("
-Reads the certificate to revoke from FILE or stdin, if omitted. It is
-an error for the file to contain more than one certificate.")
- )
- .arg(Arg::new("secret-key-file")
- .long("revocation-key").value_name("FILE")
- .help("Signs the revocation certificate using KEY")
- .long_help("
-Signs the revocation certificate using KEY. If the key is different
-from the certificate, this creates a third-party revocation. If this
-option is not provided, and the certificate includes secret key material,
-then that key is used to sign the revocation certificate.")
- )
- .arg(Arg::new("private-key-store")
- .long("private-key-store").value_name("KEY_STORE")
- .help("Provides parameters for private key store")
- )
- .arg(Arg::new("reason")
- .value_name("REASON")
- .required(true)
- .possible_values(&["compromised",
- "superseded",
- "retired",
- "unspecified"])
- .help("The reason for the revocation")
- .long_help("
-The reason for the revocation. This must be either: compromised,
-superseded, retired, or unspecified:
-
- - compromised means that the secret key material may have been
- compromised. Prefer this value if you suspect that the secret key
- has been leaked.
-
- - superseded means that the owner of the certificate has replaced it
- with a new certificate. Prefer \"compromised\" if the secret key
- material has been compromised even if the certificate is also
- being replaced! You should include the fingerprint of the new
- certificate in the message.
-
- - retired means that this certificate should not be used anymore,
- and there is no replacement. This is appropriate when someone
- leaves an organisation. Prefer \"compromised\" if the secret key
- material has been compromised even if the certificate is also
- being retired! You should include how to contact the owner, or
- who to contact instead in the message.
-
- - unspecified means that none of the three other three reasons
- apply. OpenPGP implementations conservatively treat this type of
- revocation similar to a compromised key.
-
-If the reason happened in the past, you should specify that using the
---time argument. This allows OpenPGP implementations to more
-accurately reason about objects whose validity depends on the validity
-of the certificate.")
- )
- .arg(Arg::new("message")
- .value_name("MESSAGE")
- .required(true)
- .help("A short, explanatory text")
- .long_help("
-A short, explanatory text that is shown to a viewer of the revocation
-certificate. It explains why the certificate has been revoked. For
-instance, if Alice has created a new key, she would generate a
-'superseded' revocation certificate for her old key, and might include
-the message \"I've created a new certificate, FINGERPRINT, please use
-that in the future.\"")
- )
- .arg(Arg::new("time")
- .short('t').long("time").value_name("TIME")
- .help("
-Chooses keys valid at the specified time and sets the revocation
-certificate's creation time"))
- .arg(Arg::new("notation")
- .value_names(&["NAME", "VALUE"])
- .long("notation")
- .multiple_occurrences(true).number_of_values(2)
- .help("Adds a notation to the certification.")
- .long_help("
-Adds a notation to the certification. A user-defined notation's name
-must be of the form \"name@a.domain.you.control.org\". If the
-notation's name starts with a !, then the notation is marked as being
-critical. If a consumer of a signature doesn't understand a critical
-notation, then it will ignore the signature. The notation is marked
-as being human readable."))
- .arg(Arg::new("binary")
- .short('B').long("binary")
- .help("Emits binary data"))
- )
- .subcommand(Command::new("subkey")
- .display_order(105)
- .about("Revoke a subkey")
- .long_about("
-Revokes a subkey
-
-Creates a revocation certificate for a subkey.
-
-If \"--revocation-key\" is provided, then that key is used to create
-the signature. If that key is different from the certificate being
-revoked, this creates a third-party revocation. This is normally only
-useful if the owner of the certificate designated the key to be a
-designated revoker.
-
-If \"--revocation-key\" is not provided, then the certificate must
-include a certification-capable key.")
-
- .arg(Arg::new("input")
- .value_name("FILE")
- .long("certificate")
- .alias("cert")
- .help("\
-The certificate containing the subkey to revoke")
- .long_help("
-Reads the certificate containing the subkey to revoke from FILE or stdin,
-if omitted. It is an error for the file to contain more than one
-certificate.")
- )
- .arg(Arg::new("secret-key-file")
- .long("revocation-key").value_name("FILE")
- .help("Signs the revocation certificate using KEY")
- .long_help("
-Signs the revocation certificate using KEY. If the key is different
-from the certificate, this creates a third-party revocation. If this
-option is not provided, and the certificate includes secret key material,
-then that key is used to sign the revocation certificate.")
- )
- .arg(Arg::new("private-key-store")
- .long("private-key-store").value_name("KEY_STORE")
- .help("Provides parameters for private key store")
- )
- .arg(Arg::new("subkey")
- .value_name("SUBKEY")
- .required(true)
- .help("The subkey to revoke")
- .long_help("
-The subkey to revoke. This must either be the subkey's Key ID or its
-fingerprint.")
- )
- .arg(Arg::new("reason")
- .value_name("REASON")
- .required(true)
- .possible_values(&["compromised",
- "superseded",
- "retired",
- "unspecified"])
- .help("The reason for the revocation")
- .long_help("
-The reason for the revocation. This must be either: compromised,
-superseded, retired, or unspecified:
-
- - compromised means that the secret key material may have been
- compromised. Prefer this value if you suspect that the secret key
- has been leaked.
-
- - superseded means that the owner of the certificate has replaced it
- with a new certificate. Prefer \"compromised\" if the secret key
- material has been compromised even if the certificate is also
- being replaced! You should include the fingerprint of the new
- certificate in the message.
-
- - retired means that this certificate should not be used anymore,
- and there is no replacement. This is appropriate when someone
- leaves an organisation. Prefer \"compromised\" if the secret key
- material has been compromised even if the certificate is also
- being retired! You should include how to contact the owner, or
- who to contact instead in the message.
-
- - unspecified means that none of the three other three reasons
- apply. OpenPGP implementations conservatively treat this type of
- revocation similar to a compromised key.
-
-If the reason happened in the past, you should specify that using the
---time argument. This allows OpenPGP implementations to more
-accurately reason about objects whose validity depends on the validity
-of the certificate.")
- )
- .arg(Arg::new("message")
- .value_name("MESSAGE")
- .required(true)
- .help("A short, explanatory text")
- .long_help("
-A short, explanatory text that is shown to a viewer of the revocation
-certificate. It explains why the subkey has been revoked. For
-instance, if Alice has created a new key, she would generate a
-'superseded' revocation certificate for her old key, and might include
-the message \"I've created a new subkey, please refresh the certificate.\"")
- )
- .arg(Arg::new("time")
- .short('t').long("time").value_name("TIME")
- .help("
-Chooses keys valid at the specified time and sets the revocation
-certificate's creation time"))
- .arg(Arg::new("notation")
- .value_names(&["NAME", "VALUE"])
- .long("notation")
- .multiple_occurrences(true).number_of_values(2)
- .help("Adds a notation to the certification.")
- .long_help("
-Adds a notation to the certification. A user-defined notation's name
-must be of the form \"name@a.domain.you.control.org\". If the
-notation's name starts with a !, then the notation is marked as being
-critical. If a consumer of a signature doesn't understand a critical
-notation, then it will ignore the signature. The notation is marked
-as being human readable."))
- .arg(Arg::new("binary")
- .short('B').long("binary")
- .help("Emits binary data"))
- )
- .subcommand(Command::new("userid")
- .display_order(110)
- .about("Revoke a User ID")
- .long_about("
-Revokes a User ID
-
-Creates a revocation certificate for a User ID.
-
-If \"--revocation-key\" is provided, then that key is used to create
-the signature. If that key is different from the certificate being
-revoked, this creates a third-party revocation. This is normally only
-useful if the owner of the certificate designated the key to be a
-designated revoker.
-
-If \"--revocation-key\" is not provided, then the certificate must
-include a certification-capable key.")
-
- .arg(Arg::new("input")
- .value_name("FILE")
- .long("certificate")
- .alias("cert")
- .help("
-The certificate containing the User ID to revoke")
- .long_help("
-Reads the certificate to revoke from FILE or stdin, if omitted. It is
-an error for the file to contain more than one certificate.")
- )
- .arg(Arg::new("secret-key-file")
- .long("revocation-key").value_name("FILE")
- .help("Signs the revocation certificate using KEY")
- .long_help("
-Signs the revocation certificate using KEY. If the key is different
-from the certificate, this creates a third-party revocation. If this
-option is not provided, and the certificate includes secret key material,
-then that key is used to sign the revocation certificate.")
- )
- .arg(Arg::new("private-key-store")
- .long("private-key-store").value_name("KEY_STORE")
- .help("Provides parameters for private key store")
- )
- .arg(Arg::new("userid")
- .value_name("USERID")
- .required(true)
- .help("The User ID to revoke")
- .long_help("
-
-The User ID to revoke. By default, this must exactly match a
-self-signed User ID. Use --force to generate a revocation certificate
-for a User ID, which is not self signed.")
- )
- .arg(Arg::new("reason")
- .value_name("REASON")
- .required(true)
- .possible_values(&["retired",
- "unspecified"])
- .help("The reason for the revocation")
- .long_help("
-The reason for the revocation. This must be either: retired, or
-unspecified:
-
- - retired means that this User ID is no longer valid. This is
- appropriate when someone leaves an organisation, and the
- organisation does not have their secret key material. For
- instance, if someone was part of Debian and retires, they would
- use this to indicate that a Debian-specific User ID is no longer
- valid.
-
- - unspecified means that a different reason applies.
-
-If the reason happened in the past, you should specify that using the
---time argument. This allows OpenPGP implementations to more
-accurately reason about objects whose validity depends on the validity
-of a User ID.")
- )
- .arg(Arg::new("message")
- .value_name("MESSAGE")
- .required(true)
- .help("A short, explanatory text")
- .long_help("
-A short, explanatory text that is shown to a viewer of the revocation
-certificate. It explains why the certificate has been revoked. For
-instance, if Alice has created a new key, she would generate a
-'superseded' revocation certificate for her old key, and might include
-the message \"I've created a new certificate, FINGERPRINT, please use
-that in the future.\"")
- )
- .arg(Arg::new("time")
- .short('t').long("time").value_name("TIME")
- .help("
-Chooses keys valid at the specified time and sets the revocation
-certificate's creation time"))
- .arg(Arg::new("notation")
- .value_names(&["NAME", "VALUE"])
- .long("notation")
- .multiple_occurrences(true).number_of_values(2)
- .help("Adds a notation to the certification.")
- .long_help("
-Adds a notation to the certification. A user-defined notation's name
-must be of the form \"name@a.domain.you.control.org\". If the
-notation's name starts with a !, then the notation is marked as being
-critical. If a consumer of a signature doesn't understand a critical
-notation, then it will ignore the signature. The notation is marked
-as being human readable."))
- .arg(Arg::new("binary")
- .short('B').long("binary")
- .help("Emits binary data"))
- )
);
let app = if ! feature_autocrypt {
@@ -1523,7 +1146,8 @@ as being human readable."))
.subcommand(SignCommand::command())
.subcommand(VerifyCommand::command())
.subcommand(WkdCommand::command())
- .subcommand(KeyserverCommand::command());
+ .subcommand(KeyserverCommand::command())
+ .subcommand(RevokeCommand::command());
app
}
@@ -1838,6 +1462,459 @@ pub struct SignCommand {
#[derive(Parser, Debug)]
#[clap(
+ name = "revoke",
+ display_order = 700,
+ about = "Generates revocation certificates",
+ long_about = "
+Generates revocation certificates.
+
+A revocation certificate indicates that a certificate, a subkey, a
+User ID, or a signature should not be used anymore.
+
+A revocation certificate includes two fields, a type and a
+human-readable explanation, which allows the issuer to indicate why
+the revocation certificate was issued. It is important to set the
+type field accurately as this allows an OpenPGP implementation to
+better reason about artifacts whose validity relies on the revoked
+object. For instance, if a certificate is retired, it is reasonable
+to consider signatures that it made prior to its retirement as still
+being valid. However, if a certificate's secret key material is
+compromised, any signatures that it made should be considered
+potentially forged, as they could have been made by an attacker and
+backdated.
+
+As the intent of a revocation certificate is to stop others from using
+a certificate, it is necessary to distribute the revocation
+certificate. One effective way to do this is to upload the revocation
+certificate to a keyserver.
+",
+ after_help =
+"EXAMPLES:
+
+# Revoke a certificate.
+$ sq revoke certificate --time 20220101 --certificate juliet.pgp \\
+ compromised \"My parents went through my things, and found my backup.\"
+
+# Revoke a User ID.
+$ sq revoke userid --time 20220101 --certificate juliet.pgp \\
+ \"Juliet <juliet@capuleti.it>\" retired \"I've left the family.\"
+",
+ subcommand_required = true,
+ arg_required_else_help = true,
+)]
+pub struct RevokeCommand {
+ #[clap(subcommand)]
+ pub subcommand: RevokeSubcommands,
+}
+
+#[derive(Debug, Subcommand)]
+pub enum RevokeSubcommands {
+ Certificate(RevokeCertificateCommand),
+ Subkey(RevokeSubkeyCommand),
+ Userid(RevokeUseridCommand),
+}
+
+#[derive(Debug, Args)]
+#[clap(
+ display_order = 100,
+ about = "Revoke a certificate",
+ long_about =
+"Revokes a certificate
+
+Creates a revocation certificate for the certificate.
+
+If \"--revocation-key\" is provided, then that key is used to create
+the signature. If that key is different from the certificate being
+revoked, this creates a third-party revocation. This is normally only
+useful if the owner of the certificate designated the key to be a
+designated revoker.
+
+If \"--revocation-key\" is not provided, then the certificate must
+include a certification-capable key.
+",
+)]
+pub struct RevokeCertificateCommand {
+ #[clap(
+ value_name = "FILE",
+ long = "certificate",
+ alias = "cert",
+ help = "The certificate to revoke",
+ long_help = "
+Reads the certificate to revoke from FILE or stdin, if omitted. It is
+an error for the file to contain more than one certificate.",
+ )]
+ pub input: Option<String>,
+ #[clap(
+ long = "revocation-key",
+ value_name = "KEY",
+ help = "Signs the revocation certificate using KEY",
+ long_help = "
+Signs the revocation certificate using KEY. If the key is different
+from the certificate, this creates a third-party revocation. If this
+option is not provided, and the certificate includes secret key material,
+then that key is used to sign the revocation certificate.",
+ )]
+ pub secret_key_file: Option<String>,
+ #[clap(
+ long = "private-key-store",
+ value_name = "KEY_STORE",
+ help = "Provides parameters for private key store",
+ )]
+ pub private_key_store: Option<String>,
+
+ #[clap(
+ value_name = "REASON",
+ required = true,
+ help = "The reason for the revocation",
+ long_h