diff --git a/tools/src/bin/opgpcard/cli.rs b/tools/src/bin/opgpcard/cli.rs index 2aadee6..c22125a 100644 --- a/tools/src/bin/opgpcard/cli.rs +++ b/tools/src/bin/opgpcard/cli.rs @@ -45,10 +45,7 @@ pub enum Command { Status(commands::status::StatusCommand), /// Show technical details about a card - Info { - #[clap(name = "card ident", short = 'c', long = "card")] - ident: Option, - }, + Info(commands::info::InfoCommand), /// Display a card's authentication key as an SSH public key Ssh { diff --git a/tools/src/bin/opgpcard/commands/info.rs b/tools/src/bin/opgpcard/commands/info.rs new file mode 100644 index 0000000..635e857 --- /dev/null +++ b/tools/src/bin/opgpcard/commands/info.rs @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2021-2022 Heiko Schaefer +// SPDX-FileCopyrightText: 2022 Lars Wirzenius +// SPDX-FileCopyrightText: 2022 Nora Widdecke +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use anyhow::Result; +use clap::Parser; + +use openpgp_card_sequoia::card::Card; + +use crate::output; +use crate::pick_card_for_reading; +use crate::versioned_output::{OutputBuilder, OutputFormat, OutputVersion}; + +#[derive(Parser, Debug)] +pub struct InfoCommand { + #[clap(name = "card ident", short = 'c', long = "card")] + pub ident: Option, +} + +/// print metadata information about a card +pub fn print_info( + format: OutputFormat, + output_version: OutputVersion, + command: InfoCommand, +) -> Result<()> { + let mut output = output::Info::default(); + + let backend = pick_card_for_reading(command.ident)?; + let mut card = Card::new(backend); + let mut open = card.transaction()?; + + let ai = open.application_identifier()?; + + output.ident(ai.ident()); + + let version = ai.version().to_be_bytes(); + output.card_version(format!("{}.{}", version[0], version[1])); + + output.application_id(ai.to_string()); + output.manufacturer_id(format!("{:04X}", ai.manufacturer())); + output.manufacturer_name(ai.manufacturer_name().to_string()); + + if let Some(cc) = open.historical_bytes()?.card_capabilities() { + for line in cc.to_string().lines() { + let line = line.strip_prefix("- ").unwrap_or(line); + output.card_capability(line.to_string()); + } + } + if let Some(csd) = open.historical_bytes()?.card_service_data() { + for line in csd.to_string().lines() { + let line = line.strip_prefix("- ").unwrap_or(line); + output.card_service_data(line.to_string()); + } + } + + if let Some(eli) = open.extended_length_information()? { + for line in eli.to_string().lines() { + let line = line.strip_prefix("- ").unwrap_or(line); + output.extended_length_info(line.to_string()); + } + } + + let ec = open.extended_capabilities()?; + for line in ec.to_string().lines() { + let line = line.strip_prefix("- ").unwrap_or(line); + output.extended_capability(line.to_string()); + } + + // Algorithm information (list of supported algorithms) + if let Ok(Some(ai)) = open.algorithm_information() { + for line in ai.to_string().lines() { + let line = line.strip_prefix("- ").unwrap_or(line); + output.algorithm(line.to_string()); + } + } + + // FIXME: print KDF info + + // YubiKey specific (?) firmware version + if let Ok(ver) = open.firmware_version() { + let ver = ver.iter().map(u8::to_string).collect::>().join("."); + output.firmware_version(ver); + } + + println!("{}", output.print(format, output_version)?); + + Ok(()) +} diff --git a/tools/src/bin/opgpcard/commands/mod.rs b/tools/src/bin/opgpcard/commands/mod.rs index 1cf4238..328ce90 100644 --- a/tools/src/bin/opgpcard/commands/mod.rs +++ b/tools/src/bin/opgpcard/commands/mod.rs @@ -2,4 +2,5 @@ // SPDX-FileCopyrightText: 2022 Nora Widdecke // SPDX-License-Identifier: MIT OR Apache-2.0 +pub mod info; pub mod status; diff --git a/tools/src/bin/opgpcard/main.rs b/tools/src/bin/opgpcard/main.rs index 9e0b1ea..18067f2 100644 --- a/tools/src/bin/opgpcard/main.rs +++ b/tools/src/bin/opgpcard/main.rs @@ -54,8 +54,8 @@ fn main() -> Result<(), Box> { cli::Command::Status(cmd) => { commands::status::print_status(cli.output_format, cli.output_version, cmd)?; } - cli::Command::Info { ident } => { - print_info(cli.output_format, cli.output_version, ident)?; + cli::Command::Info(cmd) => { + commands::info::print_info(cli.output_format, cli.output_version, cmd)?; } cli::Command::Ssh { ident } => { print_ssh(cli.output_format, cli.output_version, ident)?; @@ -607,76 +607,6 @@ fn pick_card_for_reading(ident: Option) -> Result, -) -> Result<()> { - let mut output = output::Info::default(); - - let backend = pick_card_for_reading(ident)?; - let mut card = Card::new(backend); - let mut open = card.transaction()?; - - let ai = open.application_identifier()?; - - output.ident(ai.ident()); - - let version = ai.version().to_be_bytes(); - output.card_version(format!("{}.{}", version[0], version[1])); - - output.application_id(ai.to_string()); - output.manufacturer_id(format!("{:04X}", ai.manufacturer())); - output.manufacturer_name(ai.manufacturer_name().to_string()); - - if let Some(cc) = open.historical_bytes()?.card_capabilities() { - for line in cc.to_string().lines() { - let line = line.strip_prefix("- ").unwrap_or(line); - output.card_capability(line.to_string()); - } - } - if let Some(csd) = open.historical_bytes()?.card_service_data() { - for line in csd.to_string().lines() { - let line = line.strip_prefix("- ").unwrap_or(line); - output.card_service_data(line.to_string()); - } - } - - if let Some(eli) = open.extended_length_information()? { - for line in eli.to_string().lines() { - let line = line.strip_prefix("- ").unwrap_or(line); - output.extended_length_info(line.to_string()); - } - } - - let ec = open.extended_capabilities()?; - for line in ec.to_string().lines() { - let line = line.strip_prefix("- ").unwrap_or(line); - output.extended_capability(line.to_string()); - } - - // Algorithm information (list of supported algorithms) - if let Ok(Some(ai)) = open.algorithm_information() { - for line in ai.to_string().lines() { - let line = line.strip_prefix("- ").unwrap_or(line); - output.algorithm(line.to_string()); - } - } - - // FIXME: print KDF info - - // YubiKey specific (?) firmware version - if let Ok(ver) = open.firmware_version() { - let ver = ver.iter().map(u8::to_string).collect::>().join("."); - output.firmware_version(ver); - } - - println!("{}", output.print(format, output_version)?); - - Ok(()) -} - fn print_ssh( format: OutputFormat, output_version: OutputVersion,