Merge branch 'nora/texts' into 'main'
Add and improve help texts See merge request openpgp-card/openpgp-card!19
This commit is contained in:
commit
d689ceb1dc
13 changed files with 350 additions and 90 deletions
|
@ -20,7 +20,7 @@ sshkeys = "0.3.2"
|
||||||
pem = "1"
|
pem = "1"
|
||||||
rpassword = "6"
|
rpassword = "6"
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
clap = { version = "3", features = ["derive"] }
|
clap = { version = "3", features = ["derive", "wrap_help"] }
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
serde_json = "1.0.86"
|
serde_json = "1.0.86"
|
||||||
|
@ -28,6 +28,7 @@ serde = { version = "1.0.145", features = ["derive"] }
|
||||||
semver = "1.0.14"
|
semver = "1.0.14"
|
||||||
serde_yaml = "0.9.13"
|
serde_yaml = "0.9.13"
|
||||||
thiserror = "1.0.37"
|
thiserror = "1.0.37"
|
||||||
|
indoc = "1"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
subplot-build = "0.5.0"
|
subplot-build = "0.5.0"
|
||||||
|
|
|
@ -33,10 +33,6 @@ pub struct Cli {
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
/// Show all output versions that are supported. Mark the
|
|
||||||
/// currently chosen one with a star.
|
|
||||||
OutputVersions {},
|
|
||||||
|
|
||||||
/// Enumerate available OpenPGP cards
|
/// Enumerate available OpenPGP cards
|
||||||
List {},
|
List {},
|
||||||
|
|
||||||
|
@ -46,7 +42,7 @@ pub enum Command {
|
||||||
/// Show technical details about a card
|
/// Show technical details about a card
|
||||||
Info(commands::info::InfoCommand),
|
Info(commands::info::InfoCommand),
|
||||||
|
|
||||||
/// Display a card's authentication key as an SSH public key
|
/// Show a card's authentication key as an SSH public key
|
||||||
Ssh(commands::ssh::SshCommand),
|
Ssh(commands::ssh::SshCommand),
|
||||||
|
|
||||||
/// Export the key data on a card as an OpenPGP public key
|
/// Export the key data on a card as an OpenPGP public key
|
||||||
|
@ -56,20 +52,60 @@ pub enum Command {
|
||||||
Admin(commands::admin::AdminCommand),
|
Admin(commands::admin::AdminCommand),
|
||||||
|
|
||||||
/// PIN management (change PINs, reset blocked PINs)
|
/// PIN management (change PINs, reset blocked PINs)
|
||||||
|
#[clap(
|
||||||
|
long_about = indoc::indoc! { "
|
||||||
|
PIN management (change PINs, reset blocked PINs)
|
||||||
|
|
||||||
|
OpenPGP cards use PINs (numerical passwords) to verify that a user is allowed to \
|
||||||
|
perform an operation. There are two PINs for regular operation, User PIN and Admin \
|
||||||
|
PIN, and one optional Resetting Code.
|
||||||
|
|
||||||
|
The User PIN is required to use cryptographic operations on a card (such as \
|
||||||
|
decryption or signing).
|
||||||
|
The Admin PIN is needed to configure a card (for example to import an OpenPGP key \
|
||||||
|
into the card) or to unblock the User PIN.
|
||||||
|
The Resetting Code only allows unblocking the User PIN. This is useful if the user \
|
||||||
|
doesn't have access to the Admin PIN.
|
||||||
|
|
||||||
|
By default, on unconfigured (or factory reset) cards, the User PIN is typically set to
|
||||||
|
123456, and the Admin PIN is set to 12345678."
|
||||||
|
},
|
||||||
|
)]
|
||||||
Pin(commands::pin::PinCommand),
|
Pin(commands::pin::PinCommand),
|
||||||
|
|
||||||
/// Decrypt data using a card
|
/// Decrypt data using a card
|
||||||
Decrypt(commands::decrypt::DecryptCommand),
|
Decrypt(commands::decrypt::DecryptCommand),
|
||||||
|
|
||||||
/// Sign data using a card
|
/// Sign data using a card
|
||||||
|
///
|
||||||
|
/// Currently, only detached signatures are supported.
|
||||||
Sign(commands::sign::SignCommand),
|
Sign(commands::sign::SignCommand),
|
||||||
|
|
||||||
/// Attestation management (Yubico)
|
/// Attestation management (Yubico only)
|
||||||
|
///
|
||||||
|
/// Yubico implements a proprietary extension to the OpenPGP card standard to
|
||||||
|
/// cryptographically certify that a certain asymmetric key has been generated on device, and
|
||||||
|
/// not imported.
|
||||||
|
///
|
||||||
|
/// This feature is available on YubiKey 5 devices with firmware version 5.2 or newer.
|
||||||
Attestation(commands::attestation::AttestationCommand),
|
Attestation(commands::attestation::AttestationCommand),
|
||||||
|
|
||||||
/// Completely reset a card (deletes all data, including the keys on the card!)
|
/// Completely reset a card (deletes all data including keys!)
|
||||||
FactoryReset(commands::factory_reset::FactoryResetCommand),
|
FactoryReset(commands::factory_reset::FactoryResetCommand),
|
||||||
|
|
||||||
/// Change identity (applies only to Nitrokey Start)
|
/// Change identity (Nitrokey Start only)
|
||||||
|
///
|
||||||
|
/// A Nitrokey Start device contains three distinct virtual OpenPGP cards, select the identity
|
||||||
|
/// of the virtual card to activate.
|
||||||
SetIdentity(commands::set_identity::SetIdentityCommand),
|
SetIdentity(commands::set_identity::SetIdentityCommand),
|
||||||
|
|
||||||
|
/// Show supported output format versions
|
||||||
|
#[clap(
|
||||||
|
long_about = indoc::indoc! { "
|
||||||
|
Show supported output format versions for JSON and YAML output.
|
||||||
|
|
||||||
|
Mark the currently chosen one with a star."
|
||||||
|
}
|
||||||
|
)]
|
||||||
|
OutputVersions {},
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,20 @@ use crate::{output, util, ENTER_ADMIN_PIN, ENTER_USER_PIN};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct AdminCommand {
|
pub struct AdminCommand {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(
|
||||||
|
name = "card ident",
|
||||||
|
short = 'c',
|
||||||
|
long = "card",
|
||||||
|
help = "Identifier of the card to use"
|
||||||
|
)]
|
||||||
pub ident: String,
|
pub ident: String,
|
||||||
|
|
||||||
#[clap(name = "Admin PIN file", short = 'P', long = "admin-pin")]
|
#[clap(
|
||||||
|
name = "Admin PIN file",
|
||||||
|
short = 'P',
|
||||||
|
long = "admin-pin",
|
||||||
|
help = "Optionally, get Admin PIN from a file"
|
||||||
|
)]
|
||||||
pub admin_pin: Option<PathBuf>,
|
pub admin_pin: Option<PathBuf>,
|
||||||
|
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
|
@ -43,66 +53,118 @@ pub struct AdminCommand {
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub enum AdminSubCommand {
|
pub enum AdminSubCommand {
|
||||||
/// Set cardholder name
|
/// Set cardholder name
|
||||||
Name { name: String },
|
Name {
|
||||||
|
#[clap(help = "cardholder name to set on the card")]
|
||||||
/// Set cardholder URL
|
name: String,
|
||||||
Url { url: String },
|
|
||||||
|
|
||||||
/// Import a Key.
|
|
||||||
///
|
|
||||||
/// If no fingerprint is provided, the key will only be imported if
|
|
||||||
/// there are zero or one (sub)keys for each key slot on the card.
|
|
||||||
Import {
|
|
||||||
keyfile: PathBuf,
|
|
||||||
|
|
||||||
#[clap(name = "Signature key fingerprint", short = 's', long = "sig-fp")]
|
|
||||||
sig_fp: Option<String>,
|
|
||||||
|
|
||||||
#[clap(name = "Decryption key fingerprint", short = 'd', long = "dec-fp")]
|
|
||||||
dec_fp: Option<String>,
|
|
||||||
|
|
||||||
#[clap(name = "Authentication key fingerprint", short = 'a', long = "auth-fp")]
|
|
||||||
auth_fp: Option<String>,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Generate a Key.
|
/// Set certificate URL
|
||||||
|
Url {
|
||||||
|
#[clap(help = "URL that provides the certificate for the key material on this card")]
|
||||||
|
url: String,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Import a Key onto the card.
|
||||||
|
///
|
||||||
|
/// Most keys can be imported without specifying subkey fingerprints. However, if the key
|
||||||
|
/// contins more than one signing, decryption or authentication capable subkey, subkeys must be
|
||||||
|
/// explicitly selected.
|
||||||
|
///
|
||||||
|
/// If any of the options is given, only the selected subkeys are imported into the selected
|
||||||
|
/// slots.
|
||||||
|
///
|
||||||
|
/// Subkey capabilities must match the slot the key is imported into. The DEC slot can
|
||||||
|
/// only be used for encryption capable subkeys. The SIG and AUT slots can be used for signing,
|
||||||
|
/// certification and authentication capable subkeys.
|
||||||
|
Import {
|
||||||
|
#[clap(help = "File that contains the PGP private key")]
|
||||||
|
keyfile: PathBuf,
|
||||||
|
|
||||||
|
/// Optionally, select the subkey to import in the SIG slot
|
||||||
|
#[clap(name = "SIG subkey fingerprint", short = 's', long = "sig-fp")]
|
||||||
|
sig_fp: Option<String>,
|
||||||
|
|
||||||
|
/// Optionally, select the subkey to import in the DEC slot
|
||||||
|
#[clap(name = "DEC subkey fingerprint", short = 'd', long = "dec-fp")]
|
||||||
|
dec_fp: Option<String>,
|
||||||
|
|
||||||
|
/// Optionally, select the subkey to import in the AUT slot
|
||||||
|
#[clap(name = "AUT subkey fingerprint", short = 'a', long = "aut-fp")]
|
||||||
|
aut_fp: Option<String>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Generate a Key on the card.
|
||||||
///
|
///
|
||||||
/// A signing key is always created, decryption and authentication keys
|
/// A signing key is always created, decryption and authentication keys
|
||||||
/// are optional.
|
/// are optional.
|
||||||
Generate(AdminGenerateCommand),
|
Generate(AdminGenerateCommand),
|
||||||
|
|
||||||
/// Set touch policy
|
/// Set the card's touch policy (if supported)
|
||||||
|
///
|
||||||
|
/// A touch policy defines if cryptographic operations on the card require user interaction
|
||||||
|
/// with the card, for example by touching a button on the card.
|
||||||
|
///
|
||||||
|
/// Only some cards support this feature at all, not all cards support all policies.
|
||||||
|
///
|
||||||
|
/// Caution: Setting the ATT slot to Fixed or Cached-Fixed is permanent. Even a factory reset does
|
||||||
|
/// not undo this setting.
|
||||||
Touch {
|
Touch {
|
||||||
|
/// Key slot to set the touch policy for
|
||||||
#[clap(name = "Key slot", short = 'k', long = "key", value_enum)]
|
#[clap(name = "Key slot", short = 'k', long = "key", value_enum)]
|
||||||
key: BasePlusAttKeySlot,
|
key: BasePlusAttKeySlot,
|
||||||
|
|
||||||
#[clap(name = "Policy", short = 'p', long = "policy", value_enum)]
|
/// Touch policy to set on this key slot
|
||||||
|
#[clap(
|
||||||
|
name = "Policy",
|
||||||
|
short = 'p',
|
||||||
|
long = "policy",
|
||||||
|
value_enum,
|
||||||
|
long_help = "Touch policy to set on this key slot
|
||||||
|
|
||||||
|
Off: No touch confirmation required.
|
||||||
|
On: Touch confirmation required for each operation.
|
||||||
|
Fixed: Like 'On', but the policy can only be changed by a reset.
|
||||||
|
Cached: Like 'On', but touch confirmation is valid for 15 seconds.
|
||||||
|
Cached-Fixed: Combines 'Cached' and 'Fixed'."
|
||||||
|
)]
|
||||||
policy: TouchPolicy,
|
policy: TouchPolicy,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct AdminGenerateCommand {
|
pub struct AdminGenerateCommand {
|
||||||
#[clap(name = "User PIN file", short = 'p', long = "user-pin")]
|
|
||||||
user_pin: Option<PathBuf>,
|
|
||||||
|
|
||||||
/// Output file
|
/// Output file
|
||||||
#[clap(name = "output", long = "output", short = 'o')]
|
#[clap(name = "output", long = "output", short = 'o')]
|
||||||
output_file: PathBuf,
|
output_file: PathBuf,
|
||||||
|
|
||||||
#[clap(long = "no-decrypt", action = clap::ArgAction::SetFalse)]
|
/// Do not create a key in the DEC slot
|
||||||
|
#[clap(long = "no-dec", action = clap::ArgAction::SetFalse)]
|
||||||
decrypt: bool,
|
decrypt: bool,
|
||||||
|
|
||||||
#[clap(long = "no-auth", action = clap::ArgAction::SetFalse)]
|
/// Do not create a key in the AUT slot
|
||||||
|
#[clap(long = "no-aut", action = clap::ArgAction::SetFalse)]
|
||||||
auth: bool,
|
auth: bool,
|
||||||
|
|
||||||
/// Algorithm
|
/// Choose the algorithm for the key material to generate on the card.
|
||||||
#[clap(value_enum)]
|
///
|
||||||
|
/// If the parameter is not given, use the algorithm currently set on the card.
|
||||||
|
///
|
||||||
|
/// Specific cards support a set of algorithms that can differ between models. On modern cards,
|
||||||
|
/// use 'opgpcard info' to see the list of supported algorithms.
|
||||||
|
#[clap(name = "algorithm", value_enum)]
|
||||||
algo: Option<Algo>,
|
algo: Option<Algo>,
|
||||||
|
|
||||||
/// User ID to add to the exported certificate representation
|
/// User ID to add to the exported certificate representation
|
||||||
#[clap(name = "User ID", short = 'u', long = "userid")]
|
#[clap(name = "User ID", short = 'u', long = "userid")]
|
||||||
user_ids: Vec<String>,
|
user_ids: Vec<String>,
|
||||||
|
|
||||||
|
#[clap(
|
||||||
|
name = "User PIN file",
|
||||||
|
short = 'p',
|
||||||
|
long = "user-pin",
|
||||||
|
help = "Optionally, get User PIN from a file"
|
||||||
|
)]
|
||||||
|
user_pin: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(ValueEnum, Debug, Clone)]
|
#[derive(ValueEnum, Debug, Clone)]
|
||||||
|
@ -161,7 +223,7 @@ pub enum Algo {
|
||||||
Nistp256,
|
Nistp256,
|
||||||
Nistp384,
|
Nistp384,
|
||||||
Nistp521,
|
Nistp521,
|
||||||
Curve25519,
|
Cv25519,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Algo> for AlgoSimple {
|
impl From<Algo> for AlgoSimple {
|
||||||
|
@ -173,7 +235,7 @@ impl From<Algo> for AlgoSimple {
|
||||||
Algo::Nistp256 => AlgoSimple::NIST256,
|
Algo::Nistp256 => AlgoSimple::NIST256,
|
||||||
Algo::Nistp384 => AlgoSimple::NIST384,
|
Algo::Nistp384 => AlgoSimple::NIST384,
|
||||||
Algo::Nistp521 => AlgoSimple::NIST521,
|
Algo::Nistp521 => AlgoSimple::NIST521,
|
||||||
Algo::Curve25519 => AlgoSimple::Curve25519,
|
Algo::Cv25519 => AlgoSimple::Curve25519,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,9 +262,9 @@ pub fn admin(
|
||||||
keyfile,
|
keyfile,
|
||||||
sig_fp,
|
sig_fp,
|
||||||
dec_fp,
|
dec_fp,
|
||||||
auth_fp,
|
aut_fp,
|
||||||
} => {
|
} => {
|
||||||
import_command(keyfile, sig_fp, dec_fp, auth_fp, card, admin_pin.as_deref())?;
|
import_command(keyfile, sig_fp, dec_fp, aut_fp, card, admin_pin.as_deref())?;
|
||||||
}
|
}
|
||||||
AdminSubCommand::Generate(cmd) => {
|
AdminSubCommand::Generate(cmd) => {
|
||||||
generate_command(
|
generate_command(
|
||||||
|
@ -238,14 +300,14 @@ fn keys_pick_explicit<'a>(
|
||||||
policy: &'a dyn Policy,
|
policy: &'a dyn Policy,
|
||||||
sig_fp: Option<String>,
|
sig_fp: Option<String>,
|
||||||
dec_fp: Option<String>,
|
dec_fp: Option<String>,
|
||||||
auth_fp: Option<String>,
|
aut_fp: Option<String>,
|
||||||
) -> Result<[Option<ValidErasedKeyAmalgamation<'a, SecretParts>>; 3]> {
|
) -> Result<[Option<ValidErasedKeyAmalgamation<'a, SecretParts>>; 3]> {
|
||||||
let key_by_fp = |fp: Option<String>| match fp {
|
let key_by_fp = |fp: Option<String>| match fp {
|
||||||
Some(fp) => sq_util::private_subkey_by_fingerprint(key, policy, &fp),
|
Some(fp) => sq_util::private_subkey_by_fingerprint(key, policy, &fp),
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok([key_by_fp(sig_fp)?, key_by_fp(dec_fp)?, key_by_fp(auth_fp)?])
|
Ok([key_by_fp(sig_fp)?, key_by_fp(dec_fp)?, key_by_fp(aut_fp)?])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_subkeys(
|
fn gen_subkeys(
|
||||||
|
@ -321,7 +383,7 @@ fn import_command(
|
||||||
keyfile: PathBuf,
|
keyfile: PathBuf,
|
||||||
sig_fp: Option<String>,
|
sig_fp: Option<String>,
|
||||||
dec_fp: Option<String>,
|
dec_fp: Option<String>,
|
||||||
auth_fp: Option<String>,
|
aut_fp: Option<String>,
|
||||||
mut card: Card<Transaction>,
|
mut card: Card<Transaction>,
|
||||||
admin_pin: Option<&[u8]>,
|
admin_pin: Option<&[u8]>,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
@ -330,12 +392,12 @@ fn import_command(
|
||||||
let p = StandardPolicy::new();
|
let p = StandardPolicy::new();
|
||||||
|
|
||||||
// select the (sub)keys to upload
|
// select the (sub)keys to upload
|
||||||
let [sig, dec, auth] = match (&sig_fp, &dec_fp, &auth_fp) {
|
let [sig, dec, auth] = match (&sig_fp, &dec_fp, &aut_fp) {
|
||||||
// No fingerprint has been provided, try to autoselect keys
|
// No fingerprint has been provided, try to autoselect keys
|
||||||
// (this fails if there is more than one (sub)key for any keytype).
|
// (this fails if there is more than one (sub)key for any keytype).
|
||||||
(&None, &None, &None) => keys_pick_yolo(&key, &p)?,
|
(&None, &None, &None) => keys_pick_yolo(&key, &p)?,
|
||||||
|
|
||||||
_ => keys_pick_explicit(&key, &p, sig_fp, dec_fp, auth_fp)?,
|
_ => keys_pick_explicit(&key, &p, sig_fp, dec_fp, aut_fp)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut pws: Vec<String> = vec![];
|
let mut pws: Vec<String> = vec![];
|
||||||
|
|
|
@ -23,30 +23,59 @@ pub struct AttestationCommand {
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub enum AttSubCommand {
|
pub enum AttSubCommand {
|
||||||
/// Print the card's "Attestation Certificate"
|
/// Print the card's attestation certificate
|
||||||
|
///
|
||||||
|
/// New YubiKeys are preloaded with an attestation certificate issued by the Yubico CA.
|
||||||
Cert {
|
Cert {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(
|
||||||
|
name = "card ident",
|
||||||
|
short = 'c',
|
||||||
|
long = "card",
|
||||||
|
help = "Identifier of the card to use"
|
||||||
|
)]
|
||||||
ident: Option<String>,
|
ident: Option<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Generate "Attestation Statement" for one of the key slots on the card
|
/// Generate attestation statement for one of the key slots on the card
|
||||||
|
///
|
||||||
|
/// An attestation statement can only be generated for key slots that contain keys that were
|
||||||
|
/// generated by the card. See 'opgpcard admin generate' and 'opgpcard status -v'.
|
||||||
Generate {
|
Generate {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(
|
||||||
|
name = "card ident",
|
||||||
|
short = 'c',
|
||||||
|
long = "card",
|
||||||
|
help = "Identifier of the card to use"
|
||||||
|
)]
|
||||||
ident: String,
|
ident: String,
|
||||||
|
|
||||||
|
/// Key slot to use
|
||||||
#[clap(name = "Key slot", short = 'k', long = "key", value_enum)]
|
#[clap(name = "Key slot", short = 'k', long = "key", value_enum)]
|
||||||
key: BaseKeySlot,
|
key: BaseKeySlot,
|
||||||
|
|
||||||
#[clap(name = "User PIN file", short = 'p', long = "user-pin")]
|
#[clap(
|
||||||
|
name = "User PIN file",
|
||||||
|
short = 'p',
|
||||||
|
long = "user-pin",
|
||||||
|
help = "Optionally, get User PIN from a file"
|
||||||
|
)]
|
||||||
user_pin: Option<PathBuf>,
|
user_pin: Option<PathBuf>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Print a "cardholder certificate" from the card.
|
/// Print the attestation statement for one of the key slots on the card
|
||||||
/// This shows the "Attestation Statement", if one has been generated.
|
///
|
||||||
|
/// An attestation statement can only be printed after generating it. See 'opgpcard attestation
|
||||||
|
/// generate'.
|
||||||
Statement {
|
Statement {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(
|
||||||
|
name = "card ident",
|
||||||
|
short = 'c',
|
||||||
|
long = "card",
|
||||||
|
help = "Identifier of the card to reset"
|
||||||
|
)]
|
||||||
ident: Option<String>,
|
ident: Option<String>,
|
||||||
|
|
||||||
|
/// Key slot to use
|
||||||
#[clap(name = "Key slot", short = 'k', long = "key", value_enum)]
|
#[clap(name = "Key slot", short = 'k', long = "key", value_enum)]
|
||||||
key: BaseKeySlot,
|
key: BaseKeySlot,
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,10 +17,20 @@ use crate::util;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct DecryptCommand {
|
pub struct DecryptCommand {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(
|
||||||
|
name = "card ident",
|
||||||
|
short = 'c',
|
||||||
|
long = "card",
|
||||||
|
help = "Identifier of the card to use"
|
||||||
|
)]
|
||||||
ident: String,
|
ident: String,
|
||||||
|
|
||||||
#[clap(name = "User PIN file", short = 'p', long = "user-pin")]
|
#[clap(
|
||||||
|
name = "User PIN file",
|
||||||
|
short = 'p',
|
||||||
|
long = "user-pin",
|
||||||
|
help = "Optionally, get User PIN from a file"
|
||||||
|
)]
|
||||||
pin_file: Option<PathBuf>,
|
pin_file: Option<PathBuf>,
|
||||||
|
|
||||||
/// Input file (stdin if unset)
|
/// Input file (stdin if unset)
|
||||||
|
|
|
@ -10,7 +10,12 @@ use crate::util;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct FactoryResetCommand {
|
pub struct FactoryResetCommand {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(
|
||||||
|
name = "card ident",
|
||||||
|
short = 'c',
|
||||||
|
long = "card",
|
||||||
|
help = "Identifier of the card to use"
|
||||||
|
)]
|
||||||
ident: String,
|
ident: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,12 @@ use crate::versioned_output::{OutputBuilder, OutputFormat, OutputVersion};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct InfoCommand {
|
pub struct InfoCommand {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(
|
||||||
|
name = "card ident",
|
||||||
|
short = 'c',
|
||||||
|
long = "card",
|
||||||
|
help = "Identifier of the card to use"
|
||||||
|
)]
|
||||||
pub ident: Option<String>,
|
pub ident: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,12 @@ use crate::{ENTER_ADMIN_PIN, ENTER_USER_PIN};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct PinCommand {
|
pub struct PinCommand {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(
|
||||||
|
name = "card ident",
|
||||||
|
short = 'c',
|
||||||
|
long = "card",
|
||||||
|
help = "Identifier of the card to use"
|
||||||
|
)]
|
||||||
pub ident: String,
|
pub ident: String,
|
||||||
|
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
|
@ -25,49 +30,111 @@ pub struct PinCommand {
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub enum PinSubCommand {
|
pub enum PinSubCommand {
|
||||||
/// Set User PIN
|
/// Set User PIN
|
||||||
|
///
|
||||||
|
/// Set a new User PIN by providing the current User PIN.
|
||||||
SetUser {
|
SetUser {
|
||||||
#[clap(name = "User PIN file old", short = 'p', long = "user-pin-old")]
|
#[clap(
|
||||||
|
name = "User PIN file old",
|
||||||
|
short = 'p',
|
||||||
|
long = "user-pin-old",
|
||||||
|
help = "Optionally, get old User PIN from a file"
|
||||||
|
)]
|
||||||
user_pin_old: Option<PathBuf>,
|
user_pin_old: Option<PathBuf>,
|
||||||
|
|
||||||
#[clap(name = "User PIN file new", short = 'q', long = "user-pin-new")]
|
#[clap(
|
||||||
|
name = "User PIN file new",
|
||||||
|
short = 'q',
|
||||||
|
long = "user-pin-new",
|
||||||
|
help = "Optionally, get new User PIN from a file"
|
||||||
|
)]
|
||||||
user_pin_new: Option<PathBuf>,
|
user_pin_new: Option<PathBuf>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Set Admin PIN
|
/// Set Admin PIN
|
||||||
|
///
|
||||||
|
/// Set a new Admin PIN by providing the current Admin PIN.
|
||||||
SetAdmin {
|
SetAdmin {
|
||||||
#[clap(name = "Admin PIN file old", short = 'P', long = "admin-pin-old")]
|
#[clap(
|
||||||
|
name = "Admin PIN file old",
|
||||||
|
short = 'P',
|
||||||
|
long = "admin-pin-old",
|
||||||
|
help = "Optionally, get old Admin PIN from a file"
|
||||||
|
)]
|
||||||
admin_pin_old: Option<PathBuf>,
|
admin_pin_old: Option<PathBuf>,
|
||||||
|
|
||||||
#[clap(name = "Admin PIN file new", short = 'Q', long = "admin-pin-new")]
|
#[clap(
|
||||||
|
name = "Admin PIN file new",
|
||||||
|
short = 'Q',
|
||||||
|
long = "admin-pin-new",
|
||||||
|
help = "Optionally, get new Admin PIN from a file"
|
||||||
|
)]
|
||||||
admin_pin_new: Option<PathBuf>,
|
admin_pin_new: Option<PathBuf>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Reset User PIN with Admin PIN
|
/// Reset User PIN with Admin PIN
|
||||||
|
///
|
||||||
|
/// Set a new User PIN by providing the Admin PIN. This can also be used if the User PIN has
|
||||||
|
/// been blocked.
|
||||||
ResetUser {
|
ResetUser {
|
||||||
#[clap(name = "Admin PIN file", short = 'P', long = "admin-pin")]
|
#[clap(
|
||||||
|
name = "Admin PIN file",
|
||||||
|
short = 'P',
|
||||||
|
long = "admin-pin",
|
||||||
|
help = "Optionally, get Admin PIN from a file"
|
||||||
|
)]
|
||||||
admin_pin: Option<PathBuf>,
|
admin_pin: Option<PathBuf>,
|
||||||
|
|
||||||
#[clap(name = "User PIN file new", short = 'p', long = "user-pin-new")]
|
#[clap(
|
||||||
|
name = "User PIN file new",
|
||||||
|
short = 'p',
|
||||||
|
long = "user-pin-new",
|
||||||
|
help = "Optionally, get new User PIN from a file"
|
||||||
|
)]
|
||||||
|
user_pin_new: Option<PathBuf>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Reset User PIN with Resetting Code
|
||||||
|
///
|
||||||
|
/// Set a new User PIN by providing the Resetting Code. This can also be used if the User PIN
|
||||||
|
/// has been blocked.
|
||||||
|
ResetUserRc {
|
||||||
|
#[clap(
|
||||||
|
name = "Resetting Code file",
|
||||||
|
short = 'r',
|
||||||
|
long = "reset-code",
|
||||||
|
help = "Optionally, get the Resetting Code from a file"
|
||||||
|
)]
|
||||||
|
reset_code: Option<PathBuf>,
|
||||||
|
|
||||||
|
#[clap(
|
||||||
|
name = "User PIN file new",
|
||||||
|
short = 'p',
|
||||||
|
long = "user-pin-new",
|
||||||
|
help = "Optionally, get new User PIN from a file"
|
||||||
|
)]
|
||||||
user_pin_new: Option<PathBuf>,
|
user_pin_new: Option<PathBuf>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Set Resetting Code
|
/// Set Resetting Code
|
||||||
|
///
|
||||||
|
/// Set a Resetting Code by providing the Admin PIN.
|
||||||
SetReset {
|
SetReset {
|
||||||
#[clap(name = "Admin PIN file", short = 'P', long = "admin-pin")]
|
#[clap(
|
||||||
|
name = "Admin PIN file",
|
||||||
|
short = 'P',
|
||||||
|
long = "admin-pin",
|
||||||
|
help = "Optionally, get Admin PIN from a file"
|
||||||
|
)]
|
||||||
admin_pin: Option<PathBuf>,
|
admin_pin: Option<PathBuf>,
|
||||||
|
|
||||||
#[clap(name = "Resetting code file", short = 'r', long = "reset-code")]
|
#[clap(
|
||||||
|
name = "Resetting Code file",
|
||||||
|
short = 'r',
|
||||||
|
long = "reset-code",
|
||||||
|
help = "Optionally, get the Resetting Code from a file"
|
||||||
|
)]
|
||||||
reset_code: Option<PathBuf>,
|
reset_code: Option<PathBuf>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Reset User PIN with 'Resetting Code'
|
|
||||||
ResetUserRc {
|
|
||||||
#[clap(name = "Resetting Code file", short = 'r', long = "reset-code")]
|
|
||||||
reset_code: Option<PathBuf>,
|
|
||||||
|
|
||||||
#[clap(name = "User PIN file new", short = 'p', long = "user-pin-new")]
|
|
||||||
user_pin_new: Option<PathBuf>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pin(ident: &str, cmd: PinSubCommand) -> Result<()> {
|
pub fn pin(ident: &str, cmd: PinSubCommand) -> Result<()> {
|
||||||
|
|
|
@ -21,10 +21,20 @@ use crate::versioned_output::{OutputBuilder, OutputFormat, OutputVersion};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct PubkeyCommand {
|
pub struct PubkeyCommand {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(
|
||||||
|
name = "card ident",
|
||||||
|
short = 'c',
|
||||||
|
long = "card",
|
||||||
|
help = "Identifier of the card to use"
|
||||||
|
)]
|
||||||
ident: Option<String>,
|
ident: Option<String>,
|
||||||
|
|
||||||
#[clap(name = "User PIN file", short = 'p', long = "user-pin")]
|
#[clap(
|
||||||
|
name = "User PIN file",
|
||||||
|
short = 'p',
|
||||||
|
long = "user-pin",
|
||||||
|
help = "Optionally, get User PIN from a file"
|
||||||
|
)]
|
||||||
user_pin: Option<PathBuf>,
|
user_pin: Option<PathBuf>,
|
||||||
|
|
||||||
/// User ID to add to the exported certificate representation
|
/// User ID to add to the exported certificate representation
|
||||||
|
|
|
@ -10,9 +10,15 @@ use crate::util;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct SetIdentityCommand {
|
pub struct SetIdentityCommand {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(
|
||||||
|
name = "card ident",
|
||||||
|
short = 'c',
|
||||||
|
long = "card",
|
||||||
|
help = "Identifier of the card to use"
|
||||||
|
)]
|
||||||
ident: String,
|
ident: String,
|
||||||
|
|
||||||
|
/// Identity of the virtual card to activate
|
||||||
#[clap(name = "identity", value_enum)]
|
#[clap(name = "identity", value_enum)]
|
||||||
id: SetIdentityId,
|
id: SetIdentityId,
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,28 @@ use crate::util;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct SignCommand {
|
pub struct SignCommand {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(
|
||||||
|
name = "card ident",
|
||||||
|
short = 'c',
|
||||||
|
long = "card",
|
||||||
|
help = "Identifier of the card to use"
|
||||||
|
)]
|
||||||
pub ident: String,
|
pub ident: String,
|
||||||
|
|
||||||
/// User PIN file
|
#[clap(
|
||||||
#[clap(short = 'p', long = "user-pin")]
|
name = "User PIN file",
|
||||||
|
short = 'p',
|
||||||
|
long = "user-pin",
|
||||||
|
help = "Optionally, get User PIN from a file"
|
||||||
|
)]
|
||||||
pub user_pin: Option<PathBuf>,
|
pub user_pin: Option<PathBuf>,
|
||||||
|
|
||||||
#[clap(name = "detached", short = 'd', long = "detached")]
|
#[clap(
|
||||||
|
name = "detached",
|
||||||
|
short = 'd',
|
||||||
|
long = "detached",
|
||||||
|
help = "Create a detached signature"
|
||||||
|
)]
|
||||||
pub detached: bool,
|
pub detached: bool,
|
||||||
|
|
||||||
/// Input file (stdin if unset)
|
/// Input file (stdin if unset)
|
||||||
|
|
|
@ -16,7 +16,12 @@ use crate::versioned_output::{OutputBuilder, OutputFormat, OutputVersion};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct SshCommand {
|
pub struct SshCommand {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(
|
||||||
|
name = "card ident",
|
||||||
|
short = 'c',
|
||||||
|
long = "card",
|
||||||
|
help = "Identifier of the card to use"
|
||||||
|
)]
|
||||||
pub ident: Option<String>,
|
pub ident: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,20 @@ use crate::versioned_output::{OutputBuilder, OutputFormat, OutputVersion};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
pub struct StatusCommand {
|
pub struct StatusCommand {
|
||||||
#[clap(name = "card ident", short = 'c', long = "card")]
|
#[clap(
|
||||||
|
name = "card ident",
|
||||||
|
short = 'c',
|
||||||
|
long = "card",
|
||||||
|
help = "Identifier of the card to use"
|
||||||
|
)]
|
||||||
pub ident: Option<String>,
|
pub ident: Option<String>,
|
||||||
|
|
||||||
#[clap(name = "verbose", short = 'v', long = "verbose")]
|
#[clap(
|
||||||
|
name = "verbose",
|
||||||
|
short = 'v',
|
||||||
|
long = "verbose",
|
||||||
|
help = "Use verbose output"
|
||||||
|
)]
|
||||||
pub verbose: bool,
|
pub verbose: bool,
|
||||||
|
|
||||||
/// Print public key material for each key slot
|
/// Print public key material for each key slot
|
||||||
|
|
Loading…
Reference in a new issue