Reorganize 'status' output format
This commit is contained in:
parent
2c666c6857
commit
15d457864c
3 changed files with 148 additions and 91 deletions
|
@ -56,36 +56,35 @@ Available OpenPGP cards:
|
|||
0007:87654321
|
||||
```
|
||||
|
||||
### Inspect cards
|
||||
### Inspect card status
|
||||
|
||||
Print status information about the data on a card.
|
||||
The card is implicitly selected (if exactly one card is connected):
|
||||
|
||||
```
|
||||
$ opgpcard status
|
||||
OpenPGP card ABCD:01234567 (card version 2.0)
|
||||
OpenPGP card ABCD:01234567 (card version 3.4)
|
||||
|
||||
Cardholder: Alice Adams
|
||||
Language preferences: 'en'
|
||||
|
||||
Signature key
|
||||
fingerprint: 1FE2 E8F1 9FE8 7D0D 8AAF 5579 8CB7 58BA 502F 2458
|
||||
created: 2022-03-25 20:15:49
|
||||
algorithm: Ed25519 (EdDSA)
|
||||
Fingerprint: 034B 348C EDA2 064C AA22 74E4 7563 E86F 5CAB C2A4
|
||||
Algorithm: Ed25519 (EdDSA)
|
||||
Created: 2022-05-21 13:15:19 UTC
|
||||
Signatures made: 11
|
||||
|
||||
Decryption key
|
||||
fingerprint: 68CB 4EDD 4D49 90B8 2CEC 2D22 EF7E 5B6A 2012 694C
|
||||
created: 2022-03-25 20:15:49
|
||||
algorithm: Cv25519 (ECDH)
|
||||
Fingerprint: 338B EE09 3950 D831 A76F 0EB9 13D6 2DF6 8C9E 5176
|
||||
Algorithm: Cv25519 (ECDH)
|
||||
Created: 2022-05-21 13:15:19 UTC
|
||||
|
||||
Authentication key
|
||||
fingerprint: 59A5 CD3E A88F 8707 D887 EAAE 1354 5F40 4E11 BE1C
|
||||
created: 2022-03-25 20:15:49
|
||||
algorithm: Ed25519 (EdDSA)
|
||||
|
||||
Retry counters: User PIN: 3, Admin PIN: 3, Resetting Code: 3
|
||||
Signature counter: 3
|
||||
Signature PIN only valid once: true
|
||||
Fingerprint: 4881 A22E 7EC6 26D1 1202 50B0 A7D7 F0D5 0C8D F719
|
||||
Algorithm: Ed25519 (EdDSA)
|
||||
Created: 2022-05-21 13:15:19 UTC
|
||||
|
||||
Remaining PIN attempts: User: 3, Admin: 3, Reset Code: 0
|
||||
```
|
||||
|
||||
Explicitly print the status information for a specific card (this command syntax is needed, when more than one card
|
||||
|
@ -95,37 +94,46 @@ is plugged in):
|
|||
$ opgpcard status --card ABCD:01234567
|
||||
```
|
||||
|
||||
Add `-v` for more verbose card status (this additionally outputs the raw public key data for each key slot):
|
||||
Add `-v` for more verbose card status:
|
||||
|
||||
```
|
||||
$ opgpcard status -c ABCD:01234567 -v
|
||||
OpenPGP card ABCD:01234567 (card version 2.0)
|
||||
OpenPGP card ABCD:01234567 (card version 3.4)
|
||||
|
||||
Cardholder: Alice Adams
|
||||
Language preferences: 'en'
|
||||
|
||||
Signature key
|
||||
fingerprint: 1FE2 E8F1 9FE8 7D0D 8AAF 5579 8CB7 58BA 502F 2458
|
||||
created: 2022-03-25 20:15:49
|
||||
algorithm: Ed25519 (EdDSA)
|
||||
public key material: ECC, data: 4C6364692AA4212AA95CF25FF31FD5F94CCAC173BFD77C918E443F09FAAFE3F5
|
||||
Fingerprint: 034B 348C EDA2 064C AA22 74E4 7563 E86F 5CAB C2A4
|
||||
Algorithm: Ed25519 (EdDSA)
|
||||
Created: 2022-05-21 13:15:19 UTC
|
||||
Touch policy: Cached [Features: Button]
|
||||
Key Status: generated
|
||||
User PIN presentation valid for unlimited signatures
|
||||
Signatures made: 11
|
||||
|
||||
Decryption key
|
||||
fingerprint: 68CB 4EDD 4D49 90B8 2CEC 2D22 EF7E 5B6A 2012 694C
|
||||
created: 2022-03-25 20:15:49
|
||||
algorithm: Cv25519 (ECDH)
|
||||
public key material: ECC, data: B99202743227D87D5F24639937DF75C936AC7933CE3328F5BF6AFA174A4A8745
|
||||
Fingerprint: 338B EE09 3950 D831 A76F 0EB9 13D6 2DF6 8C9E 5176
|
||||
Algorithm: Cv25519 (ECDH)
|
||||
Created: 2022-05-21 13:15:19 UTC
|
||||
Touch policy: Off [Features: Button]
|
||||
Key Status: generated
|
||||
|
||||
Authentication key
|
||||
fingerprint: 59A5 CD3E A88F 8707 D887 EAAE 1354 5F40 4E11 BE1C
|
||||
created: 2022-03-25 20:15:49
|
||||
algorithm: Ed25519 (EdDSA)
|
||||
public key material: ECC, data: BFE1E5EB31032E0F4320E163082BEDBAD2A6318EC368375F7A65D22AC7AB7444
|
||||
Fingerprint: 4881 A22E 7EC6 26D1 1202 50B0 A7D7 F0D5 0C8D F719
|
||||
Algorithm: Ed25519 (EdDSA)
|
||||
Created: 2022-05-21 13:15:19 UTC
|
||||
Touch policy: Off [Features: Button]
|
||||
Key Status: generated
|
||||
|
||||
Retry counters: User PIN: 3, Admin PIN: 3, Resetting Code: 3
|
||||
Signature counter: 3
|
||||
Signature PIN only valid once: true
|
||||
Remaining PIN attempts: User: 3, Admin: 3, Reset Code: 0
|
||||
|
||||
Touch policy attestation: Cached [Features: Button]
|
||||
|
||||
Key Status (#129): imported
|
||||
```
|
||||
|
||||
The `-p` flag additionally outputs the raw public key data for each key slot.
|
||||
|
||||
### Get an OpenPGP public key representation from a card
|
||||
|
||||
This command returns an OpenPGP public key representation of the keys on a card.
|
||||
|
|
|
@ -29,6 +29,10 @@ pub enum Command {
|
|||
|
||||
#[clap(name = "verbose", short = 'v', long = "verbose")]
|
||||
verbose: bool,
|
||||
|
||||
/// Print public key material for each key slot
|
||||
#[clap(name = "pkm", short = 'p', long = "public-key-material")]
|
||||
pkm: bool,
|
||||
},
|
||||
|
||||
/// Show technical details about a card
|
||||
|
|
|
@ -40,8 +40,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
println!("Available OpenPGP cards:");
|
||||
list_cards()?;
|
||||
}
|
||||
cli::Command::Status { ident, verbose } => {
|
||||
print_status(ident, verbose)?;
|
||||
cli::Command::Status {
|
||||
ident,
|
||||
verbose,
|
||||
pkm,
|
||||
} => {
|
||||
print_status(ident, verbose, pkm)?;
|
||||
}
|
||||
cli::Command::Info { ident } => {
|
||||
print_info(ident)?;
|
||||
|
@ -479,7 +483,7 @@ fn pick_card_for_reading(ident: Option<String>) -> Result<Box<dyn CardBackend +
|
|||
}
|
||||
}
|
||||
|
||||
fn print_status(ident: Option<String>, verbose: bool) -> Result<()> {
|
||||
fn print_status(ident: Option<String>, verbose: bool, pkm: bool) -> Result<()> {
|
||||
let mut card = pick_card_for_reading(ident)?;
|
||||
|
||||
let mut pgp = OpenPgp::new(&mut *card);
|
||||
|
@ -498,6 +502,9 @@ fn print_status(ident: Option<String>, verbose: bool) -> Result<()> {
|
|||
// card / cardholder metadata
|
||||
let crd = open.cardholder_related_data()?;
|
||||
|
||||
// Remember if any cardholder information is printed (if so, we print a newline later)
|
||||
let mut card_holder_output = false;
|
||||
|
||||
if let Some(name) = crd.name() {
|
||||
// FIXME: decoding as utf8 is wrong (the spec defines this field as latin1 encoded)
|
||||
let name = String::from_utf8_lossy(name).to_string();
|
||||
|
@ -518,11 +525,14 @@ fn print_status(ident: Option<String>, verbose: bool) -> Result<()> {
|
|||
let name = name.iter().cloned().rev().collect::<Vec<_>>().join(" ");
|
||||
|
||||
println!("{}", name);
|
||||
|
||||
card_holder_output = true;
|
||||
}
|
||||
|
||||
let url = open.url()?;
|
||||
if !url.is_empty() {
|
||||
println!("URL: {}", url);
|
||||
card_holder_output = true;
|
||||
}
|
||||
|
||||
if let Some(lang) = crd.lang() {
|
||||
|
@ -532,53 +542,110 @@ fn print_status(ident: Option<String>, verbose: bool) -> Result<()> {
|
|||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
println!("Language preferences: '{}'", l);
|
||||
card_holder_output = true;
|
||||
}
|
||||
|
||||
if card_holder_output {
|
||||
println!();
|
||||
}
|
||||
|
||||
// key information (imported vs. generated on card)
|
||||
let ki = ard.key_information().ok().flatten();
|
||||
|
||||
let pws = open.pw_status_bytes()?;
|
||||
|
||||
// information about subkeys
|
||||
|
||||
let fps = open.fingerprints()?;
|
||||
let kgt = open.key_generation_times()?;
|
||||
|
||||
println!();
|
||||
println!("Signature key");
|
||||
if let Some(fp) = fps.signature() {
|
||||
println!(" fingerprint: {}", fp.to_spaced_hex());
|
||||
println!(" Fingerprint: {}", fp.to_spaced_hex());
|
||||
}
|
||||
println! {" Algorithm: {}", open.algorithm_attributes(KeyType::Signing)?};
|
||||
if let Some(kgt) = kgt.signature() {
|
||||
println! {" created: {}", kgt.to_datetime()};
|
||||
println! {" Created: {}", kgt.to_datetime()};
|
||||
}
|
||||
println! {" algorithm: {}", open.algorithm_attributes(KeyType::Signing)?};
|
||||
if verbose {
|
||||
if let Some(uif) = ard.uif_pso_cds()? {
|
||||
println!(
|
||||
" Touch policy: {} [Features: {}]",
|
||||
uif.touch_policy(),
|
||||
uif.features()
|
||||
);
|
||||
}
|
||||
if let Some(ks) = ki.as_ref().map(|ki| ki.sig_status()) {
|
||||
println!(" Key Status: {}", ks);
|
||||
}
|
||||
}
|
||||
|
||||
if verbose {
|
||||
if pws.pw1_cds_valid_once() {
|
||||
println!(" User PIN presentation valid for one signature");
|
||||
} else {
|
||||
println!(" User PIN presentation valid for unlimited signatures");
|
||||
}
|
||||
}
|
||||
|
||||
let sst = open.security_support_template()?;
|
||||
println!(" Signatures made: {}", sst.signature_count());
|
||||
|
||||
if pkm {
|
||||
if let Ok(pkm) = open.public_key(KeyType::Signing) {
|
||||
println! {" public key material: {}", pkm};
|
||||
println! {" Public key material: {}", pkm};
|
||||
}
|
||||
}
|
||||
|
||||
println!();
|
||||
println!("Decryption key");
|
||||
if let Some(fp) = fps.decryption() {
|
||||
println!(" fingerprint: {}", fp.to_spaced_hex());
|
||||
println!(" Fingerprint: {}", fp.to_spaced_hex());
|
||||
}
|
||||
println! {" Algorithm: {}", open.algorithm_attributes(KeyType::Decryption)?};
|
||||
if let Some(kgt) = kgt.decryption() {
|
||||
println! {" created: {}", kgt.to_datetime()};
|
||||
println! {" Created: {}", kgt.to_datetime()};
|
||||
}
|
||||
println! {" algorithm: {}", open.algorithm_attributes(KeyType::Decryption)?};
|
||||
if verbose {
|
||||
if let Some(uif) = ard.uif_pso_dec()? {
|
||||
println!(
|
||||
" Touch policy: {} [Features: {}]",
|
||||
uif.touch_policy(),
|
||||
uif.features()
|
||||
);
|
||||
}
|
||||
if let Some(ks) = ki.as_ref().map(|ki| ki.dec_status()) {
|
||||
println!(" Key Status: {}", ks);
|
||||
}
|
||||
}
|
||||
if pkm {
|
||||
if let Ok(pkm) = open.public_key(KeyType::Decryption) {
|
||||
println! {" public key material: {}", pkm};
|
||||
println! {" Public key material: {}", pkm};
|
||||
}
|
||||
}
|
||||
|
||||
println!();
|
||||
println!("Authentication key");
|
||||
if let Some(fp) = fps.authentication() {
|
||||
println!(" fingerprint: {}", fp.to_spaced_hex());
|
||||
println!(" Fingerprint: {}", fp.to_spaced_hex());
|
||||
}
|
||||
println! {" Algorithm: {}", open.algorithm_attributes(KeyType::Authentication)?};
|
||||
if let Some(kgt) = kgt.authentication() {
|
||||
println! {" created: {}", kgt.to_datetime()};
|
||||
println! {" Created: {}", kgt.to_datetime()};
|
||||
}
|
||||
println! {" algorithm: {}", open.algorithm_attributes(KeyType::Authentication)?};
|
||||
if verbose {
|
||||
if let Some(uif) = ard.uif_pso_aut()? {
|
||||
println!(
|
||||
" Touch policy: {} [Features: {}]",
|
||||
uif.touch_policy(),
|
||||
uif.features()
|
||||
);
|
||||
}
|
||||
if let Some(ks) = ki.as_ref().map(|ki| ki.aut_status()) {
|
||||
println!(" Key Status: {}", ks);
|
||||
}
|
||||
}
|
||||
if pkm {
|
||||
if let Ok(pkm) = open.public_key(KeyType::Authentication) {
|
||||
println! {" public key material: {}", pkm};
|
||||
}
|
||||
|
@ -588,67 +655,45 @@ fn print_status(ident: Option<String>, verbose: bool) -> Result<()> {
|
|||
|
||||
println!();
|
||||
|
||||
let sst = open.security_support_template()?;
|
||||
println!("Signatures made: {}", sst.signature_count());
|
||||
|
||||
println!();
|
||||
|
||||
let pws = open.pw_status_bytes()?;
|
||||
|
||||
println!(
|
||||
"Remaining tries: User PIN: {}, Admin PIN: {}, Reset Code: {}",
|
||||
"Remaining PIN attempts: User: {}, Admin: {}, Reset Code: {}",
|
||||
pws.err_count_pw1(),
|
||||
pws.err_count_pw3(),
|
||||
pws.err_count_rc(),
|
||||
);
|
||||
println!(
|
||||
"Signature PIN only valid once: {}",
|
||||
pws.pw1_cds_valid_once()
|
||||
);
|
||||
|
||||
if verbose {
|
||||
println!();
|
||||
|
||||
if let Ok(Some(ki)) = ard.key_information() {
|
||||
println!("Key Information:\n{}", ki);
|
||||
}
|
||||
|
||||
if let Some(uif) = ard.uif_pso_cds()? {
|
||||
println!(
|
||||
"Touch policy signing: {} [Features: {}]",
|
||||
uif.touch_policy(),
|
||||
uif.features()
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(uif) = ard.uif_pso_dec()? {
|
||||
println!(
|
||||
"Touch policy decryption: {} [Features: {}]",
|
||||
uif.touch_policy(),
|
||||
uif.features()
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(uif) = ard.uif_pso_dec()? {
|
||||
println!(
|
||||
"Touch policy authentication: {} [Features: {}]",
|
||||
uif.touch_policy(),
|
||||
uif.features()
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(uif) = ard.uif_attestation()? {
|
||||
println!(
|
||||
"Touch policy attestation: {} [Features: {}]",
|
||||
uif.touch_policy(),
|
||||
uif.features()
|
||||
);
|
||||
println!();
|
||||
}
|
||||
|
||||
if let Some(ki) = ki {
|
||||
let num = ki.num_additional();
|
||||
for i in 0..num {
|
||||
println!(
|
||||
"Key Status (#{}): {}",
|
||||
ki.additional_ref(i),
|
||||
ki.additional_status(i)
|
||||
);
|
||||
}
|
||||
|
||||
if num > 0 {
|
||||
println!();
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(fps) = ard.ca_fingerprints() {
|
||||
println!();
|
||||
for x in fps.iter().enumerate() {
|
||||
println!("CA fingerprint {}: {:x?}", x.0 + 1, x.1);
|
||||
for (num, fp) in fps.iter().enumerate() {
|
||||
if let Some(fp) = fp {
|
||||
println!("CA fingerprint {}: {:x?}", num + 1, fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue