use std::path::PathBuf;
use anyhow::anyhow;
use anyhow::Result;
use clap::Parser;
use openpgp_card::ocard::KeyType;
use openpgp_card_rpgp::public_key_material_and_fp_to_key;
use crate::output;
use crate::pick_card_for_reading;
use crate::util;
use crate::versioned_output::{OutputBuilder, OutputFormat, OutputVersion};
#[derive(Parser, Debug)]
pub struct PubkeyCommand {
#[arg(
name = "card ident",
short = 'c',
long = "card",
help = "Identifier of the card to use"
)]
ident: String,
#[arg(
name = "User PIN file",
short = 'p',
long = "user-pin",
help = "Optionally, get User PIN from a file"
)]
user_pin: Option<PathBuf>,
#[arg(name = "User ID", short = 'u', long = "userid", required = true)]
user_ids: Vec<String>,
}
pub fn print_pubkey(
format: OutputFormat,
output_version: OutputVersion,
command: PubkeyCommand,
) -> Result<()> {
let mut output = output::PublicKey::default();
let mut open = pick_card_for_reading(Some(command.ident))?;
let mut card = open.transaction()?;
let ident = card.application_identifier()?.ident();
output.ident(ident);
let user_pin = util::get_pin(&mut card, command.user_pin, crate::ENTER_USER_PIN)?;
let pkm = card.public_key_material(KeyType::Signing)?;
let times = card.key_generation_times()?;
let fps = card.fingerprints()?;
let key_sig = public_key_material_and_fp_to_key(
&pkm,
KeyType::Signing,
times
.signature()
.ok_or(anyhow!("Signature time is unset"))?,
fps.signature()
.ok_or(anyhow!("Signature fingerprint is unset"))?,
)?;
let mut key_dec = None;
if let Ok(pkm) = card.public_key_material(KeyType::Decryption) {
if let Some(ts) = times.decryption() {
key_dec = Some(public_key_material_and_fp_to_key(
&pkm,
KeyType::Decryption,
ts,
fps.decryption()
.ok_or(anyhow!("Decryption fingerprint is unset"))?,
)?);
}
}
let mut key_aut = None;
if let Ok(pkm) = card.public_key_material(KeyType::Authentication) {
if let Some(ts) = times.authentication() {
key_aut = Some(public_key_material_and_fp_to_key(
&pkm,
KeyType::Authentication,
ts,
fps.authentication()
.ok_or(anyhow!("Authentication fingerprint is unset"))?,
)?);
}
}
let cert = crate::get_cert(
&mut card,
key_sig,
key_dec,
key_aut,
user_pin,
&command.user_ids,
&|| eprintln!("Enter User PIN on card reader pinpad."),
)?;
let mut buf = Vec::new();
cert.save(true, &mut buf)?;
let armored = std::str::from_utf8(buf.as_slice())?.to_string();
output.public_key(armored);
println!("{}", output.print(format, output_version)?);
Ok(())
}