opgpcard: use new Card<State> interface

This commit is contained in:
Heiko Schaefer 2022-10-27 10:55:25 +02:00
parent da65260736
commit 538fc645c5
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
13 changed files with 180 additions and 182 deletions

View file

@ -5,7 +5,7 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use clap::{Parser, ValueEnum}; use clap::{Parser, ValueEnum};
use openpgp_card_sequoia::card::{Admin, Open}; use openpgp_card_sequoia::card::{Admin, Open, Transaction};
use openpgp_card_sequoia::util::public_key_material_to_key; use openpgp_card_sequoia::util::public_key_material_to_key;
use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm}; use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm};
@ -114,7 +114,7 @@ pub enum BasePlusAttKeySlot {
Att, Att,
} }
impl From<BasePlusAttKeySlot> for openpgp_card_sequoia::types::KeyType { impl From<BasePlusAttKeySlot> for KeyType {
fn from(ks: BasePlusAttKeySlot) -> Self { fn from(ks: BasePlusAttKeySlot) -> Self {
match ks { match ks {
BasePlusAttKeySlot::Sig => KeyType::Signing, BasePlusAttKeySlot::Sig => KeyType::Signing,
@ -164,7 +164,7 @@ pub enum Algo {
Curve25519, Curve25519,
} }
impl From<Algo> for openpgp_card_sequoia::types::AlgoSimple { impl From<Algo> for AlgoSimple {
fn from(a: Algo) -> Self { fn from(a: Algo) -> Self {
match a { match a {
Algo::Rsa2048 => AlgoSimple::RSA2k, Algo::Rsa2048 => AlgoSimple::RSA2k,
@ -184,17 +184,17 @@ pub fn admin(
command: AdminCommand, command: AdminCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let backend = util::open_card(&command.ident)?; let backend = util::open_card(&command.ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
let admin_pin = util::get_pin(&mut open, command.admin_pin, ENTER_ADMIN_PIN); let admin_pin = util::get_pin(&mut card, command.admin_pin, ENTER_ADMIN_PIN);
match command.cmd { match command.cmd {
AdminSubCommand::Name { name } => { AdminSubCommand::Name { name } => {
name_command(&name, open, admin_pin.as_deref())?; name_command(&name, card, admin_pin.as_deref())?;
} }
AdminSubCommand::Url { url } => { AdminSubCommand::Url { url } => {
url_command(&url, open, admin_pin.as_deref())?; url_command(&url, card, admin_pin.as_deref())?;
} }
AdminSubCommand::Import { AdminSubCommand::Import {
keyfile, keyfile,
@ -202,19 +202,19 @@ pub fn admin(
dec_fp, dec_fp,
auth_fp, auth_fp,
} => { } => {
import_command(keyfile, sig_fp, dec_fp, auth_fp, open, admin_pin.as_deref())?; import_command(keyfile, sig_fp, dec_fp, auth_fp, card, admin_pin.as_deref())?;
} }
AdminSubCommand::Generate(cmd) => { AdminSubCommand::Generate(cmd) => {
generate_command( generate_command(
output_format, output_format,
output_version, output_version,
open, card,
admin_pin.as_deref(), admin_pin.as_deref(),
cmd, cmd,
)?; )?;
} }
AdminSubCommand::Touch { key, policy } => { AdminSubCommand::Touch { key, policy } => {
touch_command(open, admin_pin.as_deref(), key, policy)?; touch_command(card, admin_pin.as_deref(), key, policy)?;
} }
} }
Ok(()) Ok(())
@ -249,7 +249,7 @@ fn keys_pick_explicit<'a>(
} }
fn gen_subkeys( fn gen_subkeys(
admin: &mut Admin, admin: &mut Card<Admin>,
decrypt: bool, decrypt: bool,
auth: bool, auth: bool,
algo: Option<AlgoSimple>, algo: Option<AlgoSimple>,
@ -297,10 +297,10 @@ fn gen_subkeys(
fn name_command( fn name_command(
name: &str, name: &str,
mut open: Open, mut card: Card<Transaction>,
admin_pin: Option<&[u8]>, admin_pin: Option<&[u8]>,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let mut admin = util::verify_to_admin(&mut open, admin_pin)?; let mut admin = util::verify_to_admin(&mut card, admin_pin)?;
admin.set_name(name)?; admin.set_name(name)?;
Ok(()) Ok(())
@ -308,10 +308,10 @@ fn name_command(
fn url_command( fn url_command(
url: &str, url: &str,
mut open: Open, mut card: Card<Transaction>,
admin_pin: Option<&[u8]>, admin_pin: Option<&[u8]>,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let mut admin = util::verify_to_admin(&mut open, admin_pin)?; let mut admin = util::verify_to_admin(&mut card, admin_pin)?;
admin.set_url(url)?; admin.set_url(url)?;
Ok(()) Ok(())
@ -322,7 +322,7 @@ fn import_command(
sig_fp: Option<String>, sig_fp: Option<String>,
dec_fp: Option<String>, dec_fp: Option<String>,
auth_fp: Option<String>, auth_fp: Option<String>,
mut open: Open, mut card: Card<Transaction>,
admin_pin: Option<&[u8]>, admin_pin: Option<&[u8]>,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let key = Cert::from_file(keyfile)?; let key = Cert::from_file(keyfile)?;
@ -410,7 +410,7 @@ fn import_command(
let auth_p = get_pw_for_key(&auth, "authentication")?; let auth_p = get_pw_for_key(&auth, "authentication")?;
// upload keys to card // upload keys to card
let mut admin = util::verify_to_admin(&mut open, admin_pin)?; let mut admin = util::verify_to_admin(&mut card, admin_pin)?;
if let Some(sig) = sig { if let Some(sig) = sig {
println!("Uploading {} as signing key", sig.fingerprint()); println!("Uploading {} as signing key", sig.fingerprint());
@ -430,16 +430,16 @@ fn import_command(
fn generate_command( fn generate_command(
output_format: OutputFormat, output_format: OutputFormat,
output_version: OutputVersion, output_version: OutputVersion,
mut open: Open, mut card: Card<Transaction>,
admin_pin: Option<&[u8]>, admin_pin: Option<&[u8]>,
cmd: AdminGenerateCommand, cmd: AdminGenerateCommand,
) -> Result<()> { ) -> Result<()> {
let user_pin = util::get_pin(&mut open, cmd.user_pin, ENTER_USER_PIN); let user_pin = util::get_pin(&mut card, cmd.user_pin, ENTER_USER_PIN);
let mut output = output::AdminGenerate::default(); let mut output = output::AdminGenerate::default();
output.ident(open.application_identifier()?.ident()); output.ident(card.application_identifier()?.ident());
// 1) Interpret the user's choice of algorithm. // 1) Interpret the user's choice of algorithm.
// //
@ -461,7 +461,7 @@ fn generate_command(
// 2) Then, generate keys on the card. // 2) Then, generate keys on the card.
// We need "admin" access to the card for this). // We need "admin" access to the card for this).
let (key_sig, key_dec, key_aut) = { let (key_sig, key_dec, key_aut) = {
if let Ok(mut admin) = util::verify_to_admin(&mut open, admin_pin) { if let Ok(mut admin) = util::verify_to_admin(&mut card, admin_pin) {
gen_subkeys(&mut admin, cmd.decrypt, cmd.auth, algo)? gen_subkeys(&mut admin, cmd.decrypt, cmd.auth, algo)?
} else { } else {
return Err(anyhow!("Failed to open card in admin mode.")); return Err(anyhow!("Failed to open card in admin mode."));
@ -472,7 +472,7 @@ fn generate_command(
// need "signing" access to the card (to make binding signatures within // need "signing" access to the card (to make binding signatures within
// the Cert). // the Cert).
let cert = crate::get_cert( let cert = crate::get_cert(
&mut open, &mut card,
key_sig, key_sig,
key_dec, key_dec,
key_aut, key_aut,
@ -493,7 +493,7 @@ fn generate_command(
} }
fn touch_command( fn touch_command(
mut open: Open, mut card: Card<Transaction>,
admin_pin: Option<&[u8]>, admin_pin: Option<&[u8]>,
key: BasePlusAttKeySlot, key: BasePlusAttKeySlot,
policy: TouchPolicy, policy: TouchPolicy,
@ -502,7 +502,7 @@ fn touch_command(
let pol = openpgp_card_sequoia::types::TouchPolicy::from(policy); let pol = openpgp_card_sequoia::types::TouchPolicy::from(policy);
let mut admin = util::verify_to_admin(&mut open, admin_pin)?; let mut admin = util::verify_to_admin(&mut card, admin_pin)?;
admin.set_uif(kt, pol)?; admin.set_uif(kt, pol)?;
Ok(()) Ok(())

View file

@ -7,8 +7,8 @@ use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use clap::{Parser, ValueEnum}; use clap::{Parser, ValueEnum};
use openpgp_card_sequoia::card::{Card, Open};
use openpgp_card_sequoia::card::Card;
use openpgp_card_sequoia::types::KeyType; use openpgp_card_sequoia::types::KeyType;
use crate::versioned_output::{OutputBuilder, OutputFormat, OutputVersion}; use crate::versioned_output::{OutputBuilder, OutputFormat, OutputVersion};
@ -60,7 +60,7 @@ pub enum BaseKeySlot {
Aut, Aut,
} }
impl From<BaseKeySlot> for openpgp_card_sequoia::types::KeyType { impl From<BaseKeySlot> for KeyType {
fn from(ks: BaseKeySlot) -> Self { fn from(ks: BaseKeySlot) -> Self {
match ks { match ks {
BaseKeySlot::Sig => KeyType::Signing, BaseKeySlot::Sig => KeyType::Signing,
@ -94,12 +94,12 @@ fn cert(
let mut output = output::AttestationCert::default(); let mut output = output::AttestationCert::default();
let backend = pick_card_for_reading(ident)?; let backend = pick_card_for_reading(ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
output.ident(open.application_identifier()?.ident()); output.ident(card.application_identifier()?.ident());
if let Ok(ac) = open.attestation_certificate() { if let Ok(ac) = card.attestation_certificate() {
let pem = util::pem_encode(ac); let pem = util::pem_encode(ac);
output.attestation_cert(pem); output.attestation_cert(pem);
} }
@ -114,12 +114,12 @@ fn generate(
user_pin: Option<PathBuf>, user_pin: Option<PathBuf>,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let backend = util::open_card(ident)?; let backend = util::open_card(ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
let user_pin = util::get_pin(&mut open, user_pin, ENTER_USER_PIN); let user_pin = util::get_pin(&mut card, user_pin, ENTER_USER_PIN);
let mut sign = util::verify_to_sign(&mut open, user_pin.as_deref())?; let mut sign = util::verify_to_sign(&mut card, user_pin.as_deref())?;
let kt = KeyType::from(key); let kt = KeyType::from(key);
sign.generate_attestation(kt, &|| { sign.generate_attestation(kt, &|| {
@ -130,15 +130,15 @@ fn generate(
fn statement(ident: Option<String>, key: BaseKeySlot) -> Result<(), Box<dyn std::error::Error>> { fn statement(ident: Option<String>, key: BaseKeySlot) -> Result<(), Box<dyn std::error::Error>> {
let backend = pick_card_for_reading(ident)?; let backend = pick_card_for_reading(ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
// Get cardholder certificate from card. // Get cardholder certificate from card.
let mut select_data_workaround = false; let mut select_data_workaround = false;
// Use "select data" workaround if the card reports a // Use "select data" workaround if the card reports a
// yk firmware version number >= 5 and <= 5.4.3 // yk firmware version number >= 5 and <= 5.4.3
if let Ok(version) = open.firmware_version() { if let Ok(version) = card.firmware_version() {
if version.len() == 3 if version.len() == 3
&& version[0] == 5 && version[0] == 5
&& (version[1] < 4 || (version[1] == 4 && version[2] <= 3)) && (version[1] < 4 || (version[1] == 4 && version[2] <= 3))
@ -149,13 +149,13 @@ fn statement(ident: Option<String>, key: BaseKeySlot) -> Result<(), Box<dyn std:
// Select cardholder certificate // Select cardholder certificate
match key { match key {
BaseKeySlot::Aut => open.select_data(0, &[0x7F, 0x21], select_data_workaround)?, BaseKeySlot::Aut => card.select_data(0, &[0x7F, 0x21], select_data_workaround)?,
BaseKeySlot::Dec => open.select_data(1, &[0x7F, 0x21], select_data_workaround)?, BaseKeySlot::Dec => card.select_data(1, &[0x7F, 0x21], select_data_workaround)?,
BaseKeySlot::Sig => open.select_data(2, &[0x7F, 0x21], select_data_workaround)?, BaseKeySlot::Sig => card.select_data(2, &[0x7F, 0x21], select_data_workaround)?,
}; };
// Get DO "cardholder certificate" (returns the slot that was previously selected) // Get DO "cardholder certificate" (returns the slot that was previously selected)
let cert = open.cardholder_certificate()?; let cert = card.cardholder_certificate()?;
if !cert.is_empty() { if !cert.is_empty() {
let pem = util::pem_encode(cert); let pem = util::pem_encode(cert);

View file

@ -7,13 +7,12 @@ use clap::Parser;
use std::path::PathBuf; use std::path::PathBuf;
use openpgp_card_sequoia::card::{Card, Open};
use sequoia_openpgp::{ use sequoia_openpgp::{
parse::{stream::DecryptorBuilder, Parse}, parse::{stream::DecryptorBuilder, Parse},
policy::StandardPolicy, policy::StandardPolicy,
}; };
use openpgp_card_sequoia::card::Card;
use crate::util; use crate::util;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -35,16 +34,16 @@ pub fn decrypt(command: DecryptCommand) -> Result<(), Box<dyn std::error::Error>
let input = util::open_or_stdin(command.input.as_deref())?; let input = util::open_or_stdin(command.input.as_deref())?;
let backend = util::open_card(&command.ident)?; let backend = util::open_card(&command.ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
if open.fingerprints()?.decryption().is_none() { if card.fingerprints()?.decryption().is_none() {
return Err(anyhow!("Can't decrypt: this card has no key in the decryption slot.").into()); return Err(anyhow!("Can't decrypt: this card has no key in the decryption slot.").into());
} }
let user_pin = util::get_pin(&mut open, command.pin_file, crate::ENTER_USER_PIN); let user_pin = util::get_pin(&mut card, command.pin_file, crate::ENTER_USER_PIN);
let mut user = util::verify_to_user(&mut open, user_pin.as_deref())?; let mut user = util::verify_to_user(&mut card, user_pin.as_deref())?;
let d = user.decryptor(&|| println!("Touch confirmation needed for decryption"))?; let d = user.decryptor(&|| println!("Touch confirmation needed for decryption"))?;
let db = DecryptorBuilder::from_reader(input)?; let db = DecryptorBuilder::from_reader(input)?;

View file

@ -4,8 +4,7 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use clap::Parser; use clap::Parser;
use openpgp_card_sequoia::card::{Card, Open};
use openpgp_card_sequoia::card::Card;
use crate::util; use crate::util;
@ -17,9 +16,9 @@ pub struct FactoryResetCommand {
pub fn factory_reset(command: FactoryResetCommand) -> Result<()> { pub fn factory_reset(command: FactoryResetCommand) -> Result<()> {
println!("Resetting Card {}", command.ident); println!("Resetting Card {}", command.ident);
let card = util::open_card(&command.ident)?; let backend = util::open_card(&command.ident)?;
let mut card = Card::new(card); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
open.factory_reset().map_err(|e| anyhow!(e)) card.factory_reset().map_err(|e| anyhow!(e))
} }

View file

@ -5,8 +5,7 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use openpgp_card_sequoia::card::{Card, Open};
use openpgp_card_sequoia::card::Card;
use crate::output; use crate::output;
use crate::pick_card_for_reading; use crate::pick_card_for_reading;
@ -27,10 +26,10 @@ pub fn print_info(
let mut output = output::Info::default(); let mut output = output::Info::default();
let backend = pick_card_for_reading(command.ident)?; let backend = pick_card_for_reading(command.ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
let ai = open.application_identifier()?; let ai = card.application_identifier()?;
output.ident(ai.ident()); output.ident(ai.ident());
@ -41,34 +40,34 @@ pub fn print_info(
output.manufacturer_id(format!("{:04X}", ai.manufacturer())); output.manufacturer_id(format!("{:04X}", ai.manufacturer()));
output.manufacturer_name(ai.manufacturer_name().to_string()); output.manufacturer_name(ai.manufacturer_name().to_string());
if let Some(cc) = open.historical_bytes()?.card_capabilities() { if let Some(cc) = card.historical_bytes()?.card_capabilities() {
for line in cc.to_string().lines() { for line in cc.to_string().lines() {
let line = line.strip_prefix("- ").unwrap_or(line); let line = line.strip_prefix("- ").unwrap_or(line);
output.card_capability(line.to_string()); output.card_capability(line.to_string());
} }
} }
if let Some(csd) = open.historical_bytes()?.card_service_data() { if let Some(csd) = card.historical_bytes()?.card_service_data() {
for line in csd.to_string().lines() { for line in csd.to_string().lines() {
let line = line.strip_prefix("- ").unwrap_or(line); let line = line.strip_prefix("- ").unwrap_or(line);
output.card_service_data(line.to_string()); output.card_service_data(line.to_string());
} }
} }
if let Some(eli) = open.extended_length_information()? { if let Some(eli) = card.extended_length_information()? {
for line in eli.to_string().lines() { for line in eli.to_string().lines() {
let line = line.strip_prefix("- ").unwrap_or(line); let line = line.strip_prefix("- ").unwrap_or(line);
output.extended_length_info(line.to_string()); output.extended_length_info(line.to_string());
} }
} }
let ec = open.extended_capabilities()?; let ec = card.extended_capabilities()?;
for line in ec.to_string().lines() { for line in ec.to_string().lines() {
let line = line.strip_prefix("- ").unwrap_or(line); let line = line.strip_prefix("- ").unwrap_or(line);
output.extended_capability(line.to_string()); output.extended_capability(line.to_string());
} }
// Algorithm information (list of supported algorithms) // Algorithm information (list of supported algorithms)
if let Ok(Some(ai)) = open.algorithm_information() { if let Ok(Some(ai)) = card.algorithm_information() {
for line in ai.to_string().lines() { for line in ai.to_string().lines() {
let line = line.strip_prefix("- ").unwrap_or(line); let line = line.strip_prefix("- ").unwrap_or(line);
output.algorithm(line.to_string()); output.algorithm(line.to_string());
@ -78,7 +77,7 @@ pub fn print_info(
// FIXME: print KDF info // FIXME: print KDF info
// YubiKey specific (?) firmware version // YubiKey specific (?) firmware version
if let Ok(ver) = open.firmware_version() { if let Ok(ver) = card.firmware_version() {
let ver = ver.iter().map(u8::to_string).collect::<Vec<_>>().join("."); let ver = ver.iter().map(u8::to_string).collect::<Vec<_>>().join(".");
output.firmware_version(ver); output.firmware_version(ver);
} }

View file

@ -7,7 +7,7 @@ use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use openpgp_card_sequoia::card::{Card, Open}; use openpgp_card_sequoia::card::{Card, Open, Transaction};
use crate::util; use crate::util;
use crate::util::{load_pin, print_gnuk_note}; use crate::util::{load_pin, print_gnuk_note};
@ -72,51 +72,51 @@ pub enum PinSubCommand {
pub fn pin(ident: &str, cmd: PinSubCommand) -> Result<()> { pub fn pin(ident: &str, cmd: PinSubCommand) -> Result<()> {
let backend = util::open_card(ident)?; let backend = util::open_card(ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let open = card.transaction()?; let card = open.transaction()?;
match cmd { match cmd {
PinSubCommand::SetUser { PinSubCommand::SetUser {
user_pin_old, user_pin_old,
user_pin_new, user_pin_new,
} => set_user(user_pin_old, user_pin_new, open), } => set_user(user_pin_old, user_pin_new, card),
PinSubCommand::SetAdmin { PinSubCommand::SetAdmin {
admin_pin_old, admin_pin_old,
admin_pin_new, admin_pin_new,
} => set_admin(admin_pin_old, admin_pin_new, open), } => set_admin(admin_pin_old, admin_pin_new, card),
PinSubCommand::ResetUser { PinSubCommand::ResetUser {
admin_pin, admin_pin,
user_pin_new, user_pin_new,
} => reset_user(admin_pin, user_pin_new, open), } => reset_user(admin_pin, user_pin_new, card),
PinSubCommand::SetReset { PinSubCommand::SetReset {
admin_pin, admin_pin,
reset_code, reset_code,
} => set_reset(admin_pin, reset_code, open), } => set_reset(admin_pin, reset_code, card),
PinSubCommand::ResetUserRc { PinSubCommand::ResetUserRc {
reset_code, reset_code,
user_pin_new, user_pin_new,
} => reset_user_rc(reset_code, user_pin_new, open), } => reset_user_rc(reset_code, user_pin_new, card),
} }
} }
fn set_user( fn set_user(
user_pin_old: Option<PathBuf>, user_pin_old: Option<PathBuf>,
user_pin_new: Option<PathBuf>, user_pin_new: Option<PathBuf>,
mut open: Open, mut card: Card<Transaction>,
) -> Result<()> { ) -> Result<()> {
let pinpad_modify = open.feature_pinpad_modify(); let pinpad_modify = card.feature_pinpad_modify();
let res = if !pinpad_modify { let res = if !pinpad_modify {
// get current user pin // get current user pin
let user_pin1 = util::get_pin(&mut open, user_pin_old, ENTER_USER_PIN) let user_pin1 = util::get_pin(&mut card, user_pin_old, ENTER_USER_PIN)
.expect("this should never be None"); .expect("this should never be None");
// verify pin // verify pin
open.verify_user(&user_pin1)?; card.verify_user(&user_pin1)?;
println!("PIN was accepted by the card.\n"); println!("PIN was accepted by the card.\n");
let pin_new = match user_pin_new { let pin_new = match user_pin_new {
@ -128,10 +128,10 @@ fn set_user(
}; };
// set new user pin // set new user pin
open.change_user_pin(&user_pin1, &pin_new) card.change_user_pin(&user_pin1, &pin_new)
} else { } else {
// set new user pin via pinpad // set new user pin via pinpad
open.change_user_pin_pinpad(&|| { card.change_user_pin_pinpad(&|| {
println!("Enter old User PIN on card reader pinpad, then new User PIN (twice).") println!("Enter old User PIN on card reader pinpad, then new User PIN (twice).")
}) })
}; };
@ -140,7 +140,7 @@ fn set_user(
Err(err) => { Err(err) => {
println!("\nFailed to change the User PIN!"); println!("\nFailed to change the User PIN!");
println!("{:?}", err); println!("{:?}", err);
print_gnuk_note(err, &open)?; print_gnuk_note(err, &card)?;
} }
Ok(_) => println!("\nUser PIN has been set."), Ok(_) => println!("\nUser PIN has been set."),
} }
@ -150,17 +150,17 @@ fn set_user(
fn set_admin( fn set_admin(
admin_pin_old: Option<PathBuf>, admin_pin_old: Option<PathBuf>,
admin_pin_new: Option<PathBuf>, admin_pin_new: Option<PathBuf>,
mut open: Open, mut card: Card<Transaction>,
) -> Result<()> { ) -> Result<()> {
let pinpad_modify = open.feature_pinpad_modify(); let pinpad_modify = card.feature_pinpad_modify();
if !pinpad_modify { if !pinpad_modify {
// get current admin pin // get current admin pin
let admin_pin1 = util::get_pin(&mut open, admin_pin_old, ENTER_ADMIN_PIN) let admin_pin1 = util::get_pin(&mut card, admin_pin_old, ENTER_ADMIN_PIN)
.expect("this should never be None"); .expect("this should never be None");
// verify pin // verify pin
open.verify_admin(&admin_pin1)?; card.verify_admin(&admin_pin1)?;
// (Verifying the PIN here fixes this class of problems: // (Verifying the PIN here fixes this class of problems:
// https://developers.yubico.com/PGP/PGP_PIN_Change_Behavior.html // https://developers.yubico.com/PGP/PGP_PIN_Change_Behavior.html
// It is also just generally more user friendly than failing later) // It is also just generally more user friendly than failing later)
@ -175,10 +175,10 @@ fn set_admin(
}; };
// set new admin pin // set new admin pin
open.change_admin_pin(&admin_pin1, &pin_new)?; card.change_admin_pin(&admin_pin1, &pin_new)?;
} else { } else {
// set new admin pin via pinpad // set new admin pin via pinpad
open.change_admin_pin_pinpad(&|| { card.change_admin_pin_pinpad(&|| {
println!("Enter old Admin PIN on card reader pinpad, then new Admin PIN (twice).") println!("Enter old Admin PIN on card reader pinpad, then new Admin PIN (twice).")
})?; })?;
}; };
@ -190,16 +190,16 @@ fn set_admin(
fn reset_user( fn reset_user(
admin_pin: Option<PathBuf>, admin_pin: Option<PathBuf>,
user_pin_new: Option<PathBuf>, user_pin_new: Option<PathBuf>,
mut open: Open, mut card: Card<Transaction>,
) -> Result<()> { ) -> Result<()> {
// verify admin pin // verify admin pin
match util::get_pin(&mut open, admin_pin, ENTER_ADMIN_PIN) { match util::get_pin(&mut card, admin_pin, ENTER_ADMIN_PIN) {
Some(admin_pin) => { Some(admin_pin) => {
// verify pin // verify pin
open.verify_admin(&admin_pin)?; card.verify_admin(&admin_pin)?;
} }
None => { None => {
open.verify_admin_pinpad(&|| println!("Enter Admin PIN on pinpad."))?; card.verify_admin_pinpad(&|| println!("Enter Admin PIN on pinpad."))?;
} }
} }
println!("PIN was accepted by the card.\n"); println!("PIN was accepted by the card.\n");
@ -210,7 +210,7 @@ fn reset_user(
Some(path) => load_pin(&path)?, Some(path) => load_pin(&path)?,
}; };
let res = if let Some(mut admin) = open.admin_card() { let res = if let Some(mut admin) = card.admin_card() {
admin.reset_user_pin(&pin) admin.reset_user_pin(&pin)
} else { } else {
return Err(anyhow::anyhow!("Failed to use card in admin-mode.")); return Err(anyhow::anyhow!("Failed to use card in admin-mode."));
@ -219,7 +219,7 @@ fn reset_user(
match res { match res {
Err(err) => { Err(err) => {
println!("\nFailed to change the User PIN!"); println!("\nFailed to change the User PIN!");
print_gnuk_note(err, &open)?; print_gnuk_note(err, &card)?;
} }
Ok(_) => println!("\nUser PIN has been set."), Ok(_) => println!("\nUser PIN has been set."),
} }
@ -229,16 +229,16 @@ fn reset_user(
fn set_reset( fn set_reset(
admin_pin: Option<PathBuf>, admin_pin: Option<PathBuf>,
reset_code: Option<PathBuf>, reset_code: Option<PathBuf>,
mut open: Open, mut card: Card<Transaction>,
) -> Result<()> { ) -> Result<()> {
// verify admin pin // verify admin pin
match util::get_pin(&mut open, admin_pin, ENTER_ADMIN_PIN) { match util::get_pin(&mut card, admin_pin, ENTER_ADMIN_PIN) {
Some(admin_pin) => { Some(admin_pin) => {
// verify pin // verify pin
open.verify_admin(&admin_pin)?; card.verify_admin(&admin_pin)?;
} }
None => { None => {
open.verify_admin_pinpad(&|| println!("Enter Admin PIN on pinpad."))?; card.verify_admin_pinpad(&|| println!("Enter Admin PIN on pinpad."))?;
} }
} }
println!("PIN was accepted by the card.\n"); println!("PIN was accepted by the card.\n");
@ -252,7 +252,7 @@ fn set_reset(
Some(path) => load_pin(&path)?, Some(path) => load_pin(&path)?,
}; };
if let Some(mut admin) = open.admin_card() { if let Some(mut admin) = card.admin_card() {
admin.set_resetting_code(&code)?; admin.set_resetting_code(&code)?;
println!("\nResetting code has been set."); println!("\nResetting code has been set.");
Ok(()) Ok(())
@ -264,7 +264,7 @@ fn set_reset(
fn reset_user_rc( fn reset_user_rc(
reset_code: Option<PathBuf>, reset_code: Option<PathBuf>,
user_pin_new: Option<PathBuf>, user_pin_new: Option<PathBuf>,
mut open: Open, mut card: Card<Transaction>,
) -> Result<()> { ) -> Result<()> {
// reset by presenting resetting code // reset by presenting resetting code
@ -285,10 +285,10 @@ fn reset_user_rc(
}; };
// reset to new user pin // reset to new user pin
match open.reset_user_pin(&rst, &pin) { match card.reset_user_pin(&rst, &pin) {
Err(err) => { Err(err) => {
println!("\nFailed to change the User PIN!"); println!("\nFailed to change the User PIN!");
print_gnuk_note(err, &open) print_gnuk_note(err, &card)
} }
Ok(_) => { Ok(_) => {
println!("\nUser PIN has been set."); println!("\nUser PIN has been set.");

View file

@ -8,9 +8,9 @@ use clap::Parser;
use std::path::PathBuf; use std::path::PathBuf;
use openpgp_card_sequoia::card::{Card, Open};
use sequoia_openpgp::serialize::SerializeInto; use sequoia_openpgp::serialize::SerializeInto;
use openpgp_card_sequoia::card::Card;
use openpgp_card_sequoia::types::KeyType; use openpgp_card_sequoia::types::KeyType;
use openpgp_card_sequoia::util::public_key_material_and_fp_to_key; use openpgp_card_sequoia::util::public_key_material_and_fp_to_key;
@ -40,17 +40,17 @@ pub fn print_pubkey(
let mut output = output::PublicKey::default(); let mut output = output::PublicKey::default();
let backend = pick_card_for_reading(command.ident)?; let backend = pick_card_for_reading(command.ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
let ident = open.application_identifier()?.ident(); let ident = card.application_identifier()?.ident();
output.ident(ident); output.ident(ident);
let user_pin = util::get_pin(&mut open, command.user_pin, crate::ENTER_USER_PIN); let user_pin = util::get_pin(&mut card, command.user_pin, crate::ENTER_USER_PIN);
let pkm = open.public_key(KeyType::Signing)?; let pkm = card.public_key(KeyType::Signing)?;
let times = open.key_generation_times()?; let times = card.key_generation_times()?;
let fps = open.fingerprints()?; let fps = card.fingerprints()?;
let key_sig = public_key_material_and_fp_to_key( let key_sig = public_key_material_and_fp_to_key(
&pkm, &pkm,
@ -60,7 +60,7 @@ pub fn print_pubkey(
)?; )?;
let mut key_dec = None; let mut key_dec = None;
if let Ok(pkm) = open.public_key(KeyType::Decryption) { if let Ok(pkm) = card.public_key(KeyType::Decryption) {
if let Some(ts) = times.decryption() { if let Some(ts) = times.decryption() {
key_dec = Some(public_key_material_and_fp_to_key( key_dec = Some(public_key_material_and_fp_to_key(
&pkm, &pkm,
@ -72,7 +72,7 @@ pub fn print_pubkey(
} }
let mut key_aut = None; let mut key_aut = None;
if let Ok(pkm) = open.public_key(KeyType::Authentication) { if let Ok(pkm) = card.public_key(KeyType::Authentication) {
if let Some(ts) = times.authentication() { if let Some(ts) = times.authentication() {
key_aut = Some(public_key_material_and_fp_to_key( key_aut = Some(public_key_material_and_fp_to_key(
&pkm, &pkm,
@ -85,7 +85,7 @@ pub fn print_pubkey(
} }
let cert = crate::get_cert( let cert = crate::get_cert(
&mut open, &mut card,
key_sig, key_sig,
key_dec, key_dec,
key_aut, key_aut,

View file

@ -4,8 +4,7 @@
use anyhow::Result; use anyhow::Result;
use clap::{Parser, ValueEnum}; use clap::{Parser, ValueEnum};
use openpgp_card_sequoia::card::{Card, Open};
use openpgp_card_sequoia::card::Card;
use crate::util; use crate::util;
@ -40,9 +39,9 @@ impl From<SetIdentityId> for u8 {
pub fn set_identity(command: SetIdentityCommand) -> Result<(), Box<dyn std::error::Error>> { pub fn set_identity(command: SetIdentityCommand) -> Result<(), Box<dyn std::error::Error>> {
let backend = util::open_card(&command.ident)?; let backend = util::open_card(&command.ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
open.set_identity(u8::from(command.id))?; card.set_identity(u8::from(command.id))?;
Ok(()) Ok(())
} }

View file

@ -7,10 +7,9 @@ use clap::Parser;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use openpgp_card_sequoia::card::{Card, Open};
use sequoia_openpgp::serialize::stream::{Armorer, Message, Signer}; use sequoia_openpgp::serialize::stream::{Armorer, Message, Signer};
use openpgp_card_sequoia::card::Card;
use crate::util; use crate::util;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -46,16 +45,16 @@ pub fn sign_detached(
let mut input = util::open_or_stdin(input)?; let mut input = util::open_or_stdin(input)?;
let backend = util::open_card(ident)?; let backend = util::open_card(ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
if open.fingerprints()?.signature().is_none() { if card.fingerprints()?.signature().is_none() {
return Err(anyhow!("Can't sign: this card has no key in the signing slot.").into()); return Err(anyhow!("Can't sign: this card has no key in the signing slot.").into());
} }
let user_pin = util::get_pin(&mut open, pin_file, crate::ENTER_USER_PIN); let user_pin = util::get_pin(&mut card, pin_file, crate::ENTER_USER_PIN);
let mut sign = util::verify_to_sign(&mut open, user_pin.as_deref())?; let mut sign = util::verify_to_sign(&mut card, user_pin.as_deref())?;
let s = sign.signer(&|| println!("Touch confirmation needed for signing"))?; let s = sign.signer(&|| println!("Touch confirmation needed for signing"))?;
let message = Armorer::new(Message::new(std::io::stdout())).build()?; let message = Armorer::new(Message::new(std::io::stdout())).build()?;

View file

@ -5,8 +5,8 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use openpgp_card_sequoia::card::{Card, Open};
use openpgp_card_sequoia::card::Card;
use openpgp_card_sequoia::types::KeyType; use openpgp_card_sequoia::types::KeyType;
use crate::output; use crate::output;
@ -30,21 +30,21 @@ pub fn print_ssh(
let ident = command.ident; let ident = command.ident;
let backend = pick_card_for_reading(ident)?; let backend = pick_card_for_reading(ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
let ident = open.application_identifier()?.ident(); let ident = card.application_identifier()?.ident();
output.ident(ident.clone()); output.ident(ident.clone());
// Print fingerprint of authentication subkey // Print fingerprint of authentication subkey
let fps = open.fingerprints()?; let fps = card.fingerprints()?;
if let Some(fp) = fps.authentication() { if let Some(fp) = fps.authentication() {
output.authentication_key_fingerprint(fp.to_string()); output.authentication_key_fingerprint(fp.to_string());
} }
// Show authentication subkey as openssh public key string // Show authentication subkey as openssh public key string
if let Ok(pkm) = open.public_key(KeyType::Authentication) { if let Ok(pkm) = card.public_key(KeyType::Authentication) {
if let Ok(ssh) = util::get_ssh_pubkey_string(&pkm, ident) { if let Ok(ssh) = util::get_ssh_pubkey_string(&pkm, ident) {
output.ssh_public_key(ssh); output.ssh_public_key(ssh);
} }

View file

@ -5,8 +5,8 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use openpgp_card_sequoia::card::{Card, Open};
use openpgp_card_sequoia::card::Card;
use openpgp_card_sequoia::types::KeyType; use openpgp_card_sequoia::types::KeyType;
use crate::output; use crate::output;
@ -35,17 +35,17 @@ pub fn print_status(
output.verbose(command.verbose); output.verbose(command.verbose);
let backend = pick_card_for_reading(command.ident)?; let backend = pick_card_for_reading(command.ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
output.ident(open.application_identifier()?.ident()); output.ident(card.application_identifier()?.ident());
let ai = open.application_identifier()?; let ai = card.application_identifier()?;
let version = ai.version().to_be_bytes(); let version = ai.version().to_be_bytes();
output.card_version(format!("{}.{}", version[0], version[1])); output.card_version(format!("{}.{}", version[0], version[1]));
// card / cardholder metadata // card / cardholder metadata
let crd = open.cardholder_related_data()?; let crd = card.cardholder_related_data()?;
if let Some(name) = crd.name() { if let Some(name) = crd.name() {
// FIXME: decoding as utf8 is wrong (the spec defines this field as latin1 encoded) // FIXME: decoding as utf8 is wrong (the spec defines this field as latin1 encoded)
@ -67,7 +67,7 @@ pub fn print_status(
output.card_holder(name); output.card_holder(name);
} }
let url = open.url()?; let url = card.url()?;
if !url.is_empty() { if !url.is_empty() {
output.url(url); output.url(url);
} }
@ -79,24 +79,24 @@ pub fn print_status(
} }
// key information (imported vs. generated on card) // key information (imported vs. generated on card)
let ki = open.key_information().ok().flatten(); let ki = card.key_information().ok().flatten();
let pws = open.pw_status_bytes()?; let pws = card.pw_status_bytes()?;
// information about subkeys // information about subkeys
let fps = open.fingerprints()?; let fps = card.fingerprints()?;
let kgt = open.key_generation_times()?; let kgt = card.key_generation_times()?;
let mut signature_key = output::KeySlotInfo::default(); let mut signature_key = output::KeySlotInfo::default();
if let Some(fp) = fps.signature() { if let Some(fp) = fps.signature() {
signature_key.fingerprint(fp.to_spaced_hex()); signature_key.fingerprint(fp.to_spaced_hex());
} }
signature_key.algorithm(format!("{}", open.algorithm_attributes(KeyType::Signing)?)); signature_key.algorithm(format!("{}", card.algorithm_attributes(KeyType::Signing)?));
if let Some(kgt) = kgt.signature() { if let Some(kgt) = kgt.signature() {
signature_key.created(format!("{}", kgt.to_datetime())); signature_key.created(format!("{}", kgt.to_datetime()));
} }
if let Some(uif) = open.uif_signing()? { if let Some(uif) = card.uif_signing()? {
signature_key.touch_policy(format!("{}", uif.touch_policy())); signature_key.touch_policy(format!("{}", uif.touch_policy()));
signature_key.touch_features(format!("{}", uif.features())); signature_key.touch_features(format!("{}", uif.features()));
} }
@ -109,14 +109,14 @@ pub fn print_status(
} }
if command.pkm { if command.pkm {
if let Ok(pkm) = open.public_key(KeyType::Signing) { if let Ok(pkm) = card.public_key(KeyType::Signing) {
signature_key.public_key_material(pkm.to_string()); signature_key.public_key_material(pkm.to_string());
} }
} }
output.signature_key(signature_key); output.signature_key(signature_key);
let sst = open.security_support_template()?; let sst = card.security_support_template()?;
output.signature_count(sst.signature_count()); output.signature_count(sst.signature_count());
let mut decryption_key = output::KeySlotInfo::default(); let mut decryption_key = output::KeySlotInfo::default();
@ -125,12 +125,12 @@ pub fn print_status(
} }
decryption_key.algorithm(format!( decryption_key.algorithm(format!(
"{}", "{}",
open.algorithm_attributes(KeyType::Decryption)? card.algorithm_attributes(KeyType::Decryption)?
)); ));
if let Some(kgt) = kgt.decryption() { if let Some(kgt) = kgt.decryption() {
decryption_key.created(format!("{}", kgt.to_datetime())); decryption_key.created(format!("{}", kgt.to_datetime()));
} }
if let Some(uif) = open.uif_decryption()? { if let Some(uif) = card.uif_decryption()? {
decryption_key.touch_policy(format!("{}", uif.touch_policy())); decryption_key.touch_policy(format!("{}", uif.touch_policy()));
decryption_key.touch_features(format!("{}", uif.features())); decryption_key.touch_features(format!("{}", uif.features()));
} }
@ -138,7 +138,7 @@ pub fn print_status(
decryption_key.status(format!("{}", ks)); decryption_key.status(format!("{}", ks));
} }
if command.pkm { if command.pkm {
if let Ok(pkm) = open.public_key(KeyType::Decryption) { if let Ok(pkm) = card.public_key(KeyType::Decryption) {
decryption_key.public_key_material(pkm.to_string()); decryption_key.public_key_material(pkm.to_string());
} }
} }
@ -150,12 +150,12 @@ pub fn print_status(
} }
authentication_key.algorithm(format!( authentication_key.algorithm(format!(
"{}", "{}",
open.algorithm_attributes(KeyType::Authentication)? card.algorithm_attributes(KeyType::Authentication)?
)); ));
if let Some(kgt) = kgt.authentication() { if let Some(kgt) = kgt.authentication() {
authentication_key.created(format!("{}", kgt.to_datetime())); authentication_key.created(format!("{}", kgt.to_datetime()));
} }
if let Some(uif) = open.uif_authentication()? { if let Some(uif) = card.uif_authentication()? {
authentication_key.touch_policy(format!("{}", uif.touch_policy())); authentication_key.touch_policy(format!("{}", uif.touch_policy()));
authentication_key.touch_features(format!("{}", uif.features())); authentication_key.touch_features(format!("{}", uif.features()));
} }
@ -163,7 +163,7 @@ pub fn print_status(
authentication_key.status(format!("{}", ks)); authentication_key.status(format!("{}", ks));
} }
if command.pkm { if command.pkm {
if let Ok(pkm) = open.public_key(KeyType::Authentication) { if let Ok(pkm) = card.public_key(KeyType::Authentication) {
authentication_key.public_key_material(pkm.to_string()); authentication_key.public_key_material(pkm.to_string());
} }
} }
@ -180,7 +180,7 @@ pub fn print_status(
// own `Option<KeySlotInfo>`, and (if any information about the // own `Option<KeySlotInfo>`, and (if any information about the
// attestation key exists at all, which is not the case for most // attestation key exists at all, which is not the case for most
// cards) it should be printed as a fourth KeySlot block. // cards) it should be printed as a fourth KeySlot block.
if let Some(uif) = open.uif_attestation()? { if let Some(uif) = card.uif_attestation()? {
output.card_touch_policy(uif.touch_policy().to_string()); output.card_touch_policy(uif.touch_policy().to_string());
output.card_touch_features(uif.features().to_string()); output.card_touch_features(uif.features().to_string());
} }
@ -192,7 +192,7 @@ pub fn print_status(
} }
} }
if let Ok(fps) = open.ca_fingerprints() { if let Ok(fps) = card.ca_fingerprints() {
for fp in fps.iter().flatten() { for fp in fps.iter().flatten() {
output.ca_fingerprint(fp.to_string()); output.ca_fingerprint(fp.to_string());
} }

View file

@ -8,7 +8,7 @@ use clap::Parser;
use sequoia_openpgp::Cert; use sequoia_openpgp::Cert;
use openpgp_card_sequoia::card::{Card, Open}; use openpgp_card_sequoia::card::{Card, Open, Transaction};
use openpgp_card_sequoia::types::CardBackend; use openpgp_card_sequoia::types::CardBackend;
use openpgp_card_sequoia::util::make_cert; use openpgp_card_sequoia::util::make_cert;
use openpgp_card_sequoia::PublicKey; use openpgp_card_sequoia::PublicKey;
@ -90,10 +90,9 @@ fn list_cards(format: OutputFormat, output_version: OutputVersion) -> Result<()>
let mut output = output::List::default(); let mut output = output::List::default();
if !cards.is_empty() { if !cards.is_empty() {
for backend in cards { for backend in cards {
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let open = card.transaction()?;
output.push(open.application_identifier()?.ident()); output.push(open.transaction()?.application_identifier()?.ident());
} }
} }
println!("{}", output.print(format, output_version)?); println!("{}", output.print(format, output_version)?);
@ -123,7 +122,7 @@ fn pick_card_for_reading(ident: Option<String>) -> Result<Box<dyn CardBackend +
} }
fn get_cert( fn get_cert(
open: &mut Open, card: &mut Card<Transaction>,
key_sig: PublicKey, key_sig: PublicKey,
key_dec: Option<PublicKey>, key_dec: Option<PublicKey>,
key_aut: Option<PublicKey>, key_aut: Option<PublicKey>,
@ -131,7 +130,7 @@ fn get_cert(
user_ids: &[String], user_ids: &[String],
prompt: &dyn Fn(), prompt: &dyn Fn(),
) -> Result<Cert> { ) -> Result<Cert> {
if user_pin.is_none() && open.feature_pinpad_verify() { if user_pin.is_none() && card.feature_pinpad_verify() {
println!( println!(
"The public cert will now be generated.\n\n\ "The public cert will now be generated.\n\n\
You will need to enter your User PIN multiple times during this process.\n\n" You will need to enter your User PIN multiple times during this process.\n\n"
@ -139,7 +138,7 @@ fn get_cert(
} }
make_cert( make_cert(
open, card,
key_sig, key_sig,
key_dec, key_dec,
key_aut, key_aut,

View file

@ -5,7 +5,7 @@ use anyhow::{anyhow, Context, Result};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use openpgp_card_pcsc::PcscBackend; use openpgp_card_pcsc::PcscBackend;
use openpgp_card_sequoia::card::{Admin, Open, Sign, User}; use openpgp_card_sequoia::card::{Admin, Card, Sign, Transaction, User};
use openpgp_card_sequoia::types::{ use openpgp_card_sequoia::types::{
Algo, CardBackend, Curve, EccType, Error, PublicKeyMaterial, StatusBytes, Algo, CardBackend, Curve, EccType, Error, PublicKeyMaterial, StatusBytes,
}; };
@ -23,11 +23,15 @@ pub(crate) fn open_card(ident: &str) -> Result<Box<dyn CardBackend + Send + Sync
/// If a pinpad is available, return Null (the pinpad will be used to get access to the card). /// If a pinpad is available, return Null (the pinpad will be used to get access to the card).
/// ///
/// `msg` is the message to show when asking the user to enter a PIN. /// `msg` is the message to show when asking the user to enter a PIN.
pub(crate) fn get_pin(open: &mut Open, pin_file: Option<PathBuf>, msg: &str) -> Option<Vec<u8>> { pub(crate) fn get_pin(
card: &mut Card<Transaction<'_>>,
pin_file: Option<PathBuf>,
msg: &str,
) -> Option<Vec<u8>> {
if let Some(path) = pin_file { if let Some(path) = pin_file {
// we have a pin file // we have a pin file
Some(load_pin(&path).ok()?) Some(load_pin(&path).ok()?)
} else if !open.feature_pinpad_verify() { } else if !card.feature_pinpad_verify() {
// we have no pin file and no pinpad // we have no pin file and no pinpad
let pin = rpassword::prompt_password(msg).ok()?; let pin = rpassword::prompt_password(msg).ok()?;
Some(pin.into_bytes()) Some(pin.into_bytes())
@ -51,53 +55,53 @@ pub(crate) fn input_pin_twice(msg1: &str, msg2: &str) -> Result<Vec<u8>> {
} }
pub(crate) fn verify_to_user<'app, 'open>( pub(crate) fn verify_to_user<'app, 'open>(
open: &'open mut Open<'app>, card: &'open mut Card<Transaction<'app>>,
pin: Option<&[u8]>, pin: Option<&[u8]>,
) -> Result<User<'app, 'open>, Box<dyn std::error::Error>> { ) -> Result<Card<User<'app, 'open>>, Box<dyn std::error::Error>> {
if let Some(pin) = pin { if let Some(pin) = pin {
open.verify_user(pin)?; card.verify_user(pin)?;
} else { } else {
if !open.feature_pinpad_verify() { if !card.feature_pinpad_verify() {
return Err(anyhow!("No user PIN file provided, and no pinpad found").into()); return Err(anyhow!("No user PIN file provided, and no pinpad found").into());
}; };
open.verify_user_pinpad(&|| println!("Enter user PIN on card reader pinpad."))?; card.verify_user_pinpad(&|| println!("Enter user PIN on card reader pinpad."))?;
} }
open.user_card() card.user_card()
.ok_or_else(|| anyhow!("Couldn't get user access").into()) .ok_or_else(|| anyhow!("Couldn't get user access").into())
} }
pub(crate) fn verify_to_sign<'app, 'open>( pub(crate) fn verify_to_sign<'app, 'open>(
open: &'open mut Open<'app>, card: &'open mut Card<Transaction<'app>>,
pin: Option<&[u8]>, pin: Option<&[u8]>,
) -> Result<Sign<'app, 'open>, Box<dyn std::error::Error>> { ) -> Result<Card<Sign<'app, 'open>>, Box<dyn std::error::Error>> {
if let Some(pin) = pin { if let Some(pin) = pin {
open.verify_user_for_signing(pin)?; card.verify_user_for_signing(pin)?;
} else { } else {
if !open.feature_pinpad_verify() { if !card.feature_pinpad_verify() {
return Err(anyhow!("No user PIN file provided, and no pinpad found").into()); return Err(anyhow!("No user PIN file provided, and no pinpad found").into());
} }
open.verify_user_for_signing_pinpad(&|| println!("Enter user PIN on card reader pinpad."))?; card.verify_user_for_signing_pinpad(&|| println!("Enter user PIN on card reader pinpad."))?;
} }
open.signing_card() card.signing_card()
.ok_or_else(|| anyhow!("Couldn't get sign access").into()) .ok_or_else(|| anyhow!("Couldn't get sign access").into())
} }
pub(crate) fn verify_to_admin<'app, 'open>( pub(crate) fn verify_to_admin<'app, 'open>(
open: &'open mut Open<'app>, card: &'open mut Card<Transaction<'app>>,
pin: Option<&[u8]>, pin: Option<&[u8]>,
) -> Result<Admin<'app, 'open>, Box<dyn std::error::Error>> { ) -> Result<Card<Admin<'app, 'open>>, Box<dyn std::error::Error>> {
if let Some(pin) = pin { if let Some(pin) = pin {
open.verify_admin(pin)?; card.verify_admin(pin)?;
} else { } else {
if !open.feature_pinpad_verify() { if !card.feature_pinpad_verify() {
return Err(anyhow!("No admin PIN file provided, and no pinpad found").into()); return Err(anyhow!("No admin PIN file provided, and no pinpad found").into());
} }
open.verify_admin_pinpad(&|| println!("Enter admin PIN on card reader pinpad."))?; card.verify_admin_pinpad(&|| println!("Enter admin PIN on card reader pinpad."))?;
} }
open.admin_card() card.admin_card()
.ok_or_else(|| anyhow!("Couldn't get admin access").into()) .ok_or_else(|| anyhow!("Couldn't get admin access").into())
} }
@ -215,7 +219,7 @@ pub(crate) fn get_ssh_pubkey_string(pkm: &PublicKeyMaterial, ident: String) -> R
/// This fn checks for Gnuk's Status code and the case that no keys exist /// This fn checks for Gnuk's Status code and the case that no keys exist
/// on the card, and prints a note to the user, pointing out that the /// on the card, and prints a note to the user, pointing out that the
/// absence of keys on the card might be the reason for the error they get. /// absence of keys on the card might be the reason for the error they get.
pub(crate) fn print_gnuk_note(err: Error, card: &Open) -> Result<()> { pub(crate) fn print_gnuk_note(err: Error, card: &Card<Transaction>) -> Result<()> {
if matches!( if matches!(
err, err,
Error::CardStatus(StatusBytes::ConditionOfUseNotSatisfied) Error::CardStatus(StatusBytes::ConditionOfUseNotSatisfied)