Tweak ergonomics of openpgp-card-pcsc usage and simplify client code.

This commit is contained in:
Heiko Schaefer 2022-02-18 11:11:37 +01:00
parent 635fa0e6ac
commit e01c79e857
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
10 changed files with 47 additions and 44 deletions

View file

@ -9,7 +9,7 @@ use pcsc::ShareMode;
use serde_derive::Deserialize; use serde_derive::Deserialize;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use openpgp_card::Error; use openpgp_card::{CardBackend, Error};
use openpgp_card_pcsc::PcscCard; use openpgp_card_pcsc::PcscCard;
use openpgp_card_scdc::ScdClient; use openpgp_card_scdc::ScdClient;
@ -41,7 +41,7 @@ pub struct TestCardData {
} }
impl TestCardData { impl TestCardData {
pub(crate) fn get_card(&self) -> Result<Box<PcscCard>> { pub(crate) fn get_card(&self) -> Result<Box<dyn CardBackend>> {
self.tc.open() self.tc.open()
} }
@ -92,7 +92,7 @@ pub enum TestCard {
} }
impl TestCard { impl TestCard {
pub fn open(&self) -> Result<Box<PcscCard>> { pub fn open(&self) -> Result<Box<dyn CardBackend>> {
match self { match self {
Self::Pcsc(ident) => { Self::Pcsc(ident) => {
// Attempt to shutdown SCD, if it is running. // Attempt to shutdown SCD, if it is running.
@ -103,11 +103,11 @@ impl TestCard {
// Make three attempts to open the card before failing // Make three attempts to open the card before failing
// (this can be useful in ShareMode::Exclusive) // (this can be useful in ShareMode::Exclusive)
let mut i = 1; let mut i = 1;
let card: Result<PcscCard, Error> = loop { let card: Result<Box<dyn CardBackend>, Error> = loop {
let res = PcscCard::open_by_ident(ident, SHARE_MODE); let res = PcscCard::open_by_ident(ident, SHARE_MODE);
if i == 3 || res.is_ok() { if i == 3 || res.is_ok() {
break res; break res.map(Into::into);
} }
// sleep for 100ms // sleep for 100ms
@ -116,7 +116,7 @@ impl TestCard {
i += 1; i += 1;
}; };
Ok(Box::new(card?)) Ok(card?)
} }
Self::Scdc(serial) => { Self::Scdc(serial) => {
unimplemented!(); unimplemented!();

View file

@ -11,7 +11,7 @@ fn main() -> Result<()> {
println!("The following OpenPGP cards are connected to your system:"); println!("The following OpenPGP cards are connected to your system:");
for mut card in PcscCard::cards(None)? { for mut card in PcscCard::cards(None)? {
let mut txc = <dyn CardBackend>::transaction(&mut card)?; let mut txc = card.transaction()?;
let open = Open::new(&mut *txc)?; let open = Open::new(&mut *txc)?;
println!(" {}", open.application_identifier()?.ident()); println!(" {}", open.application_identifier()?.ident());

View file

@ -15,9 +15,7 @@ use sequoia_openpgp::Cert;
use openpgp_card; use openpgp_card;
use openpgp_card::algorithm::AlgoSimple; use openpgp_card::algorithm::AlgoSimple;
use openpgp_card::card_do::{KeyGenerationTime, Sex}; use openpgp_card::card_do::{KeyGenerationTime, Sex};
use openpgp_card::{ use openpgp_card::{CardTransaction, Error, KeyType, StatusBytes};
CardBackend, CardTransaction, Error, KeyType, StatusBytes,
};
use openpgp_card_sequoia::card::Open; use openpgp_card_sequoia::card::Open;
use openpgp_card_sequoia::util::{ use openpgp_card_sequoia::util::{
make_cert, public_key_material_to_key, public_to_fingerprint, make_cert, public_key_material_to_key, public_to_fingerprint,
@ -680,8 +678,7 @@ pub fn run_test(
param: &[&str], param: &[&str],
) -> Result<TestOutput, TestError> { ) -> Result<TestOutput, TestError> {
let mut card = tc.get_card()?; let mut card = tc.get_card()?;
let mut txc = let mut txc = card.transaction().map_err(|e| anyhow!(e))?;
<dyn CardBackend>::transaction(&mut *card).map_err(|e| anyhow!(e))?;
t(&mut *txc, param) t(&mut *txc, param)
} }

View file

@ -23,7 +23,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let cert_file = &args[2]; let cert_file = &args[2];
let mut card = PcscCard::open_by_ident(card_ident, None)?; let mut card = PcscCard::open_by_ident(card_ident, None)?;
let mut txc = <dyn CardBackend>::transaction(&mut card)?; let mut txc = card.transaction()?;
let mut open = Open::new(&mut *txc)?; let mut open = Open::new(&mut *txc)?;

View file

@ -23,7 +23,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let cert_file = &args[2]; let cert_file = &args[2];
let mut card = PcscCard::open_by_ident(card_ident, None)?; let mut card = PcscCard::open_by_ident(card_ident, None)?;
let mut txc = <dyn CardBackend>::transaction(&mut card)?; let mut txc = card.transaction()?;
let mut open = Open::new(&mut *txc)?; let mut open = Open::new(&mut *txc)?;

View file

@ -12,13 +12,13 @@
//! With `openpgp-card-pcsc` you can either open all available cards: //! With `openpgp-card-pcsc` you can either open all available cards:
//! //!
//! ```no_run //! ```no_run
//! use openpgp_card_sequoia::card::Open;
//! use openpgp_card_pcsc::PcscCard; //! use openpgp_card_pcsc::PcscCard;
//! use openpgp_card::CardBackend;
//! use openpgp_card_sequoia::card::Open;
//! //!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # use openpgp_card::CardBackend;
//! for mut card in PcscCard::cards(None)? { //! for mut card in PcscCard::cards(None)? {
//! let mut txc = <dyn CardBackend>::transaction(&mut card)?; //! let mut txc = card.transaction()?;
//! let open = Open::new(&mut *txc)?; //! let open = Open::new(&mut *txc)?;
//! println!("Found OpenPGP card with ident '{}'", //! println!("Found OpenPGP card with ident '{}'",
//! open.application_identifier()?.ident()); //! open.application_identifier()?.ident());
@ -30,13 +30,13 @@
//! Or you can open one particular card, by ident: //! Or you can open one particular card, by ident:
//! //!
//! ```no_run //! ```no_run
//! use openpgp_card_sequoia::card::Open;
//! use openpgp_card_pcsc::PcscCard; //! use openpgp_card_pcsc::PcscCard;
//! use openpgp_card::CardBackend;
//! use openpgp_card_sequoia::card::Open;
//! //!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # use openpgp_card::CardBackend;
//! let mut card = PcscCard::open_by_ident("abcd:12345678", None)?; //! let mut card = PcscCard::open_by_ident("abcd:12345678", None)?;
//! let mut txc = <dyn CardBackend>::transaction(&mut card)?; //! let mut txc = card.transaction()?;
//! let mut open = Open::new(&mut *txc)?; //! let mut open = Open::new(&mut *txc)?;
//! # Ok(()) //! # Ok(())
//! # } //! # }
@ -52,15 +52,15 @@
//! that corresponds to the private encryption key on the card: //! that corresponds to the private encryption key on the card:
//! //!
//! ```no_run //! ```no_run
//! use openpgp_card_sequoia::card::Open;
//! use openpgp_card_pcsc::PcscCard; //! use openpgp_card_pcsc::PcscCard;
//! use openpgp_card::CardBackend;
//! use openpgp_card_sequoia::card::Open;
//! //!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Open card via PCSC //! // Open card via PCSC
//! use sequoia_openpgp::policy::StandardPolicy; //! use sequoia_openpgp::policy::StandardPolicy;
//! # use openpgp_card::CardBackend;
//! let mut card = PcscCard::open_by_ident("abcd:12345678", None)?; //! let mut card = PcscCard::open_by_ident("abcd:12345678", None)?;
//! let mut txc = <dyn CardBackend>::transaction(&mut card)?; //! let mut txc = card.transaction()?;
//! let mut open = Open::new(&mut *txc)?; //! let mut open = Open::new(&mut *txc)?;
//! //!
//! // Get authorization for user access to the card with password //! // Get authorization for user access to the card with password
@ -95,15 +95,15 @@
//! user password before each signing operation!) //! user password before each signing operation!)
//! //!
//! ```no_run //! ```no_run
//! use openpgp_card_sequoia::card::Open;
//! use openpgp_card_pcsc::PcscCard; //! use openpgp_card_pcsc::PcscCard;
//! use openpgp_card::CardBackend;
//! use openpgp_card_sequoia::card::Open;
//! //!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # use openpgp_card::CardBackend;
//! // Open card via PCSC //! // Open card via PCSC
//! use sequoia_openpgp::policy::StandardPolicy; //! use sequoia_openpgp::policy::StandardPolicy;
//! let mut card = PcscCard::open_by_ident("abcd:12345678", None)?; //! let mut card = PcscCard::open_by_ident("abcd:12345678", None)?;
//! let mut txc = <dyn CardBackend>::transaction(&mut card)?; //! let mut txc = card.transaction()?;
//! let mut open = Open::new(&mut *txc)?; //! let mut open = Open::new(&mut *txc)?;
//! //!
//! // Get authorization for signing access to the card with password //! // Get authorization for signing access to the card with password
@ -128,14 +128,14 @@
//! # Setting up and configuring a card //! # Setting up and configuring a card
//! //!
//! ```no_run //! ```no_run
//! use openpgp_card_sequoia::card::Open;
//! use openpgp_card_pcsc::PcscCard; //! use openpgp_card_pcsc::PcscCard;
//! use openpgp_card::CardBackend;
//! use openpgp_card_sequoia::card::Open;
//! //!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # use openpgp_card::CardBackend;
//! // Open card via PCSC //! // Open card via PCSC
//! let mut card = PcscCard::open_by_ident("abcd:12345678", None)?; //! let mut card = PcscCard::open_by_ident("abcd:12345678", None)?;
//! let mut txc = <dyn CardBackend>::transaction(&mut card)?; //! let mut txc = card.transaction()?;
//! let mut open = Open::new(&mut *txc)?; //! let mut open = Open::new(&mut *txc)?;
//! //!
//! // Get authorization for admin access to the card with password //! // Get authorization for admin access to the card with password

View file

@ -10,8 +10,7 @@ use sequoia_openpgp::policy::StandardPolicy;
use sequoia_openpgp::Cert; use sequoia_openpgp::Cert;
use openpgp_card::card_do::Sex; use openpgp_card::card_do::Sex;
use openpgp_card::CardBackend; use openpgp_card::{CardBackend, KeyType};
use openpgp_card::KeyType;
use openpgp_card_pcsc::PcscCard; use openpgp_card_pcsc::PcscCard;
use openpgp_card_sequoia::card::Open; use openpgp_card_sequoia::card::Open;

View file

@ -40,6 +40,12 @@ pub struct PcscCard {
reader_caps: HashMap<u8, Tlv>, reader_caps: HashMap<u8, Tlv>,
} }
impl From<PcscCard> for Box<dyn CardBackend> {
fn from(card: PcscCard) -> Box<dyn CardBackend> {
Box::new(card) as Box<dyn CardBackend>
}
}
/// An implementation of the CardTransaction trait that uses the PCSC lite /// An implementation of the CardTransaction trait that uses the PCSC lite
/// middleware to access the OpenPGP card application on smart cards, via a /// middleware to access the OpenPGP card application on smart cards, via a
/// PCSC "transaction". /// PCSC "transaction".
@ -446,11 +452,11 @@ impl CardTransaction for TxClient<'_> {
} }
impl PcscCard { impl PcscCard {
pub fn card(&mut self) -> &mut Card { fn card(&mut self) -> &mut Card {
&mut self.card &mut self.card
} }
pub fn mode(&self) -> ShareMode { fn mode(&self) -> ShareMode {
self.mode self.mode
} }
@ -529,8 +535,8 @@ impl PcscCard {
fn cards_filter( fn cards_filter(
ident: Option<&str>, ident: Option<&str>,
mode: ShareMode, mode: ShareMode,
) -> Result<Vec<PcscCard>, Error> { ) -> Result<Vec<Self>, Error> {
let mut cas: Vec<PcscCard> = vec![]; let mut cards: Vec<Self> = vec![];
for mut card in for mut card in
Self::raw_pcsc_cards(mode).map_err(|sce| Error::Smartcard(sce))? Self::raw_pcsc_cards(mode).map_err(|sce| Error::Smartcard(sce))?
@ -588,20 +594,20 @@ impl PcscCard {
if store_card { if store_card {
let pcsc = PcscCard::new(card, mode); let pcsc = PcscCard::new(card, mode);
cas.push(pcsc.initialize_card()?); cards.push(pcsc.initialize_card()?);
} }
} }
log::debug!("cards_filter: found {} cards", cas.len()); log::debug!("cards_filter: found {} cards", cards.len());
Ok(cas) Ok(cards)
} }
/// Return all cards on which the OpenPGP application could be selected. /// Return all cards on which the OpenPGP application could be selected.
/// ///
/// Each card has the OpenPGP application selected, card_caps and reader_caps have been /// Each card has the OpenPGP application selected, card_caps and reader_caps have been
/// initialized. /// initialized.
pub fn cards(mode: Option<ShareMode>) -> Result<Vec<PcscCard>, Error> { pub fn cards(mode: Option<ShareMode>) -> Result<Vec<Self>, Error> {
Self::cards_filter(None, default_mode(mode)) Self::cards_filter(None, default_mode(mode))
} }
@ -611,7 +617,7 @@ impl PcscCard {
pub fn open_by_ident( pub fn open_by_ident(
ident: &str, ident: &str,
mode: Option<ShareMode>, mode: Option<ShareMode>,
) -> Result<PcscCard, Error> { ) -> Result<Self, Error> {
log::debug!("open_by_ident for {:?}", ident); log::debug!("open_by_ident for {:?}", ident);
let mut cards = Self::cards_filter(Some(ident), default_mode(mode))?; let mut cards = Self::cards_filter(Some(ident), default_mode(mode))?;

View file

@ -12,7 +12,6 @@ use sequoia_openpgp::serialize::SerializeInto;
use sequoia_openpgp::Cert; use sequoia_openpgp::Cert;
use openpgp_card::algorithm::AlgoSimple; use openpgp_card::algorithm::AlgoSimple;
use openpgp_card::CardBackend;
use openpgp_card::{card_do::Sex, KeyType}; use openpgp_card::{card_do::Sex, KeyType};
use openpgp_card_sequoia::card::{Admin, Open}; use openpgp_card_sequoia::card::{Admin, Open};

View file

@ -6,16 +6,18 @@ use std::path::{Path, PathBuf};
use openpgp_card::algorithm::{Algo, Curve}; use openpgp_card::algorithm::{Algo, Curve};
use openpgp_card::crypto_data::{EccType, PublicKeyMaterial}; use openpgp_card::crypto_data::{EccType, PublicKeyMaterial};
use openpgp_card::Error; use openpgp_card::{CardBackend, Error};
use openpgp_card_pcsc::PcscCard; use openpgp_card_pcsc::PcscCard;
use openpgp_card_sequoia::card::{Admin, Open, Sign, User}; use openpgp_card_sequoia::card::{Admin, Open, Sign, User};
pub(crate) fn cards() -> Result<Vec<PcscCard>, Error> { pub(crate) fn cards() -> Result<Vec<Box<dyn CardBackend>>, Error> {
PcscCard::cards(None) PcscCard::cards(None)
.map(|cards| cards.into_iter().map(Into::into).collect())
} }
pub(crate) fn open_card(ident: &str) -> Result<PcscCard, Error> { pub(crate) fn open_card(ident: &str) -> Result<Box<dyn CardBackend>, Error> {
PcscCard::open_by_ident(ident, None) PcscCard::open_by_ident(ident, None)
.map(|pc| Box::new(pc) as Box<dyn CardBackend>)
} }
pub(crate) fn verify_to_user<'app, 'open>( pub(crate) fn verify_to_user<'app, 'open>(