opgpcard: Extract pubkey command into module

This commit is contained in:
Nora Widdecke 2022-10-26 11:48:16 +02:00
parent 660ba2d3bb
commit 3ff4127fff
No known key found for this signature in database
GPG key ID: 2D4111B31DBB99B6
4 changed files with 107 additions and 97 deletions

View file

@ -51,17 +51,7 @@ pub enum Command {
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
Pubkey { Pubkey(commands::pubkey::PubkeyCommand),
#[clap(name = "card ident", short = 'c', long = "card")]
ident: Option<String>,
#[clap(name = "User PIN file", short = 'p', long = "user-pin")]
user_pin: Option<PathBuf>,
/// User ID to add to the exported certificate representation
#[clap(name = "User ID", short = 'u', long = "userid")]
user_id: Vec<String>,
},
/// Administer data on a card (including keys and metadata) /// Administer data on a card (including keys and metadata)
Admin { Admin {

View file

@ -3,5 +3,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
pub mod info; pub mod info;
pub mod pubkey;
pub mod ssh; pub mod ssh;
pub mod status; pub mod status;

View file

@ -0,0 +1,102 @@
// SPDX-FileCopyrightText: 2021-2022 Heiko Schaefer <heiko@schaefer.name>
// SPDX-FileCopyrightText: 2022 Lars Wirzenius <liw@liw.fi>
// SPDX-FileCopyrightText: 2022 Nora Widdecke <mail@nora.pink>
// SPDX-License-Identifier: MIT OR Apache-2.0
use anyhow::Result;
use clap::Parser;
use std::path::PathBuf;
use sequoia_openpgp::serialize::SerializeInto;
use openpgp_card_sequoia::card::Card;
use openpgp_card_sequoia::types::KeyType;
use openpgp_card_sequoia::util::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 {
#[clap(name = "card ident", short = 'c', long = "card")]
ident: Option<String>,
#[clap(name = "User PIN file", short = 'p', long = "user-pin")]
user_pin: Option<PathBuf>,
/// User ID to add to the exported certificate representation
#[clap(name = "User ID", short = 'u', long = "userid")]
user_ids: Vec<String>,
}
pub fn print_pubkey(
format: OutputFormat,
output_version: OutputVersion,
command: PubkeyCommand,
) -> Result<()> {
let mut output = output::PublicKey::default();
let backend = pick_card_for_reading(command.ident)?;
let mut card = Card::new(backend);
let mut open = card.transaction()?;
let ident = open.application_identifier()?.ident();
output.ident(ident);
let user_pin = util::get_pin(&mut open, command.user_pin, crate::ENTER_USER_PIN);
let pkm = open.public_key(KeyType::Signing)?;
let times = open.key_generation_times()?;
let fps = open.fingerprints()?;
let key_sig = public_key_material_and_fp_to_key(
&pkm,
KeyType::Signing,
times.signature().expect("Signature time is unset"),
fps.signature().expect("Signature fingerprint is unset"),
)?;
let mut key_dec = None;
if let Ok(pkm) = open.public_key(KeyType::Decryption) {
if let Some(ts) = times.decryption() {
key_dec = Some(public_key_material_and_fp_to_key(
&pkm,
KeyType::Decryption,
ts,
fps.decryption().expect("Decryption fingerprint is unset"),
)?);
}
}
let mut key_aut = None;
if let Ok(pkm) = open.public_key(KeyType::Authentication) {
if let Some(ts) = times.authentication() {
key_aut = Some(public_key_material_and_fp_to_key(
&pkm,
KeyType::Authentication,
ts,
fps.authentication()
.expect("Authentication fingerprint is unset"),
)?);
}
}
let cert = crate::get_cert(
&mut open,
key_sig,
key_dec,
key_aut,
user_pin.as_deref(),
&command.user_ids,
&|| println!("Enter User PIN on card reader pinpad."),
)?;
let armored = String::from_utf8(cert.armored().to_vec()?)?;
output.public_key(armored);
println!("{}", output.print(format, output_version)?);
Ok(())
}

View file

@ -19,9 +19,7 @@ use sequoia_openpgp::Cert;
use openpgp_card_sequoia::card::{Admin, Card, Open}; use openpgp_card_sequoia::card::{Admin, Card, Open};
use openpgp_card_sequoia::types::{AlgoSimple, CardBackend, KeyType, TouchPolicy}; use openpgp_card_sequoia::types::{AlgoSimple, CardBackend, KeyType, TouchPolicy};
use openpgp_card_sequoia::util::{ use openpgp_card_sequoia::util::{make_cert, public_key_material_to_key};
make_cert, public_key_material_and_fp_to_key, public_key_material_to_key,
};
use openpgp_card_sequoia::{sq_util, PublicKey}; use openpgp_card_sequoia::{sq_util, PublicKey};
use crate::util::{load_pin, print_gnuk_note}; use crate::util::{load_pin, print_gnuk_note};
@ -60,18 +58,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
cli::Command::Ssh(cmd) => { cli::Command::Ssh(cmd) => {
commands::ssh::print_ssh(cli.output_format, cli.output_version, cmd)?; commands::ssh::print_ssh(cli.output_format, cli.output_version, cmd)?;
} }
cli::Command::Pubkey { cli::Command::Pubkey(cmd) => {
ident, commands::pubkey::print_pubkey(cli.output_format, cli.output_version, cmd)?;
user_pin,
user_id,
} => {
print_pubkey(
cli.output_format,
cli.output_version,
ident,
user_pin,
user_id,
)?;
} }
cli::Command::SetIdentity { ident, id } => { cli::Command::SetIdentity { ident, id } => {
set_identity(&ident, id)?; set_identity(&ident, id)?;
@ -607,77 +595,6 @@ fn pick_card_for_reading(ident: Option<String>) -> Result<Box<dyn CardBackend +
} }
} }
fn print_pubkey(
format: OutputFormat,
output_version: OutputVersion,
ident: Option<String>,
user_pin: Option<PathBuf>,
user_ids: Vec<String>,
) -> Result<()> {
let mut output = output::PublicKey::default();
let backend = pick_card_for_reading(ident)?;
let mut card = Card::new(backend);
let mut open = card.transaction()?;
let ident = open.application_identifier()?.ident();
output.ident(ident);
let user_pin = util::get_pin(&mut open, user_pin, ENTER_USER_PIN);
let pkm = open.public_key(KeyType::Signing)?;
let times = open.key_generation_times()?;
let fps = open.fingerprints()?;
let key_sig = public_key_material_and_fp_to_key(
&pkm,
KeyType::Signing,
times.signature().expect("Signature time is unset"),
fps.signature().expect("Signature fingerprint is unset"),
)?;
let mut key_dec = None;
if let Ok(pkm) = open.public_key(KeyType::Decryption) {
if let Some(ts) = times.decryption() {
key_dec = Some(public_key_material_and_fp_to_key(
&pkm,
KeyType::Decryption,
ts,
fps.decryption().expect("Decryption fingerprint is unset"),
)?);
}
}
let mut key_aut = None;
if let Ok(pkm) = open.public_key(KeyType::Authentication) {
if let Some(ts) = times.authentication() {
key_aut = Some(public_key_material_and_fp_to_key(
&pkm,
KeyType::Authentication,
ts,
fps.authentication()
.expect("Authentication fingerprint is unset"),
)?);
}
}
let cert = get_cert(
&mut open,
key_sig,
key_dec,
key_aut,
user_pin.as_deref(),
&user_ids,
&|| println!("Enter User PIN on card reader pinpad."),
)?;
let armored = String::from_utf8(cert.armored().to_vec()?)?;
output.public_key(armored);
println!("{}", output.print(format, output_version)?);
Ok(())
}
fn decrypt( fn decrypt(
ident: &str, ident: &str,
pin_file: Option<PathBuf>, pin_file: Option<PathBuf>,