diff options
author | Nora Widdecke <nora@sequoia-pgp.org> | 2022-06-03 08:52:00 +0200 |
---|---|---|
committer | Nora Widdecke <nora@sequoia-pgp.org> | 2022-06-08 14:49:43 +0200 |
commit | 207d4ba7b7fe9844ddc54c8962a4ce0c7f6fb0ba (patch) | |
tree | 139056a04654372c7df3ba14a587c61a428c9788 /sq | |
parent | 09cb68ffcd7ea7943d5aa55ce2e20618c3daeb40 (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.rs | 63 | ||||
-rw-r--r-- | sq/src/sq_cli.rs | 833 |
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 |