Implement a macro "start_tx!" for DRY transaction starting

This commit is contained in:
Heiko Schaefer 2022-01-10 11:59:41 +01:00
parent 748c334403
commit b367043a12
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
2 changed files with 67 additions and 87 deletions

View file

@ -19,6 +19,65 @@ use openpgp_card::{CardApp, CardCaps, CardClient, Error, SmartcardError};
const FEATURE_VERIFY_PIN_DIRECT: u8 = 0x06; const FEATURE_VERIFY_PIN_DIRECT: u8 = 0x06;
const FEATURE_MODIFY_PIN_DIRECT: u8 = 0x07; const FEATURE_MODIFY_PIN_DIRECT: u8 = 0x07;
macro_rules! start_tx {
($card:expr) => {{
let mut was_reset = false;
loop {
let res = $card.transaction();
match res {
Ok(mut tx) => {
// A transaction has been successfully started
if was_reset {
log::debug!(
"start_tx: card was reset, select() openpgp"
);
let mut txc = TxClient::new(&mut tx);
TxClient::select(&mut txc)?;
}
break tx;
}
Err(pcsc::Error::ResetCard) => {
// Card was reset, need to reconnect
was_reset = true;
drop(res);
log::debug!("start_tx: do reconnect");
{
$card
.reconnect(
ShareMode::Shared,
Protocols::ANY,
Disposition::ResetCard,
)
.map_err(|e| {
Error::Smartcard(SmartcardError::Error(
format!("Reconnect failed: {:?}", e),
))
})?;
}
log::debug!("start_tx: reconnected.");
// -> try opening a transaction again
}
Err(e) => {
log::debug!("start_tx: error {:?}", e);
return Err(Error::Smartcard(SmartcardError::Error(
format!("Error: {:?}", e),
)));
}
};
}
}};
}
/// An implementation of the CardClient trait that uses the PCSC lite /// An implementation of the CardClient trait that uses the PCSC lite
/// middleware to access the OpenPGP card application on smart cards. /// middleware to access the OpenPGP card application on smart cards.
pub struct PcscClient { pub struct PcscClient {
@ -177,10 +236,12 @@ impl PcscClient {
} }
} }
fn cards_filter(ident: Option<&str>) -> Result<Vec<CardApp>> { fn cards_filter(ident: Option<&str>) -> Result<Vec<CardApp>, Error> {
let mut cas: Vec<CardApp> = vec![]; let mut cas: Vec<CardApp> = vec![];
for mut card in Self::raw_pcsc_cards()? { for mut card in
Self::raw_pcsc_cards().map_err(|sce| Error::Smartcard(sce))?
{
log::debug!("cards_filter: next card"); log::debug!("cards_filter: next card");
let stat = card.status2_owned(); let stat = card.status2_owned();
@ -190,37 +251,8 @@ impl PcscClient {
{ {
// start transaction // start transaction
log::debug!("1"); log::debug!("1");
let mut tx: Transaction = start_tx!(card);
let mut tx = loop {
let res = card.transaction();
match res {
Ok(tx) => break tx,
Err(pcsc::Error::ResetCard) => {
// Card was reset, need to reconnect
drop(res);
log::debug!("1a");
{
card.reconnect(
ShareMode::Shared,
Protocols::ANY,
Disposition::ResetCard,
)?;
}
log::debug!("1b");
// try again
}
Err(e) => {
return Err(e.into());
}
};
};
log::debug!("2");
let mut txc = TxClient::new(&mut tx); let mut txc = TxClient::new(&mut tx);
log::debug!("3"); log::debug!("3");
{ {
@ -284,7 +316,7 @@ impl PcscClient {
/// ///
/// Each card has the OpenPGP application selected, CardCaps have been /// Each card has the OpenPGP application selected, CardCaps have been
/// initialized. /// initialized.
pub fn cards() -> Result<Vec<CardApp>> { pub fn cards() -> Result<Vec<CardApp>, Error> {
Self::cards_filter(None) Self::cards_filter(None)
} }
@ -377,62 +409,10 @@ impl CardClient for PcscClient {
cmd: &[u8], cmd: &[u8],
buf_size: usize, buf_size: usize,
) -> Result<Vec<u8>, Error> { ) -> Result<Vec<u8>, Error> {
let mut was_reset = false;
let stat = self.card.status2_owned(); let stat = self.card.status2_owned();
log::debug!("PcscClient transmit - status2: {:x?}", stat); log::debug!("PcscClient transmit - status2: {:x?}", stat);
let mut tx = loop { let mut tx: Transaction = start_tx!(self.card);
let res = self.card.transaction();
match res {
Ok(mut tx) => {
// A transaction has been successfully started
if was_reset {
log::debug!("card was reset, select() openpgp");
let mut txc = TxClient::new(&mut tx);
TxClient::select(&mut txc)?;
}
break tx;
}
Err(pcsc::Error::ResetCard) => {
// Error getting Transaction.
// Card was reset -> need to reconnect.
was_reset = true;
drop(res);
log::debug!("PcscClient transmit 1a");
{
self.card
.reconnect(
ShareMode::Shared,
Protocols::ANY,
Disposition::ResetCard,
)
.map_err(|e| {
Error::Smartcard(SmartcardError::Error(
format!("Reconnect failed: {:?}", e),
))
})?;
}
log::debug!("PcscClient transmit 1b");
// try again
}
Err(e) => {
return Err(Error::Smartcard(SmartcardError::Error(
format!("Error: {:?}", e),
)));
}
};
};
log::debug!("PcscClient transmit 2"); log::debug!("PcscClient transmit 2");
let mut txc = TxClient::new(&mut tx); let mut txc = TxClient::new(&mut tx);

View file

@ -8,7 +8,7 @@ use openpgp_card::{CardApp, Error};
use openpgp_card_pcsc::PcscClient; use openpgp_card_pcsc::PcscClient;
use openpgp_card_sequoia::card::{Admin, Open, Sign, User}; use openpgp_card_sequoia::card::{Admin, Open, Sign, User};
pub(crate) fn cards() -> Result<Vec<CardApp>> { pub(crate) fn cards() -> Result<Vec<CardApp>, Error> {
PcscClient::cards() PcscClient::cards()
} }