From 53f637e0a1fe26f110d2e00a8bf555d8aa731aa6 Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Tue, 18 Jan 2022 22:41:20 +0100 Subject: [PATCH] Change transaction-starting macro to consume a PcscCard and produce a TxClient. Rename: start_tx!->get_txc!. --- card-functionality/src/list-cards.rs | 8 +-- card-functionality/src/tests.rs | 11 +--- pcsc/src/lib.rs | 88 +++++++++++++++++----------- 3 files changed, 58 insertions(+), 49 deletions(-) diff --git a/card-functionality/src/list-cards.rs b/card-functionality/src/list-cards.rs index 7a9df6f..0908c83 100644 --- a/card-functionality/src/list-cards.rs +++ b/card-functionality/src/list-cards.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use anyhow::Result; -use pcsc::Transaction; use openpgp_card_pcsc::{PcscCard, TxClient}; use openpgp_card_sequoia::card::Open; @@ -11,12 +10,7 @@ fn main() -> Result<()> { println!("The following OpenPGP cards are connected to your system:"); for mut card in PcscCard::cards()? { - let cc = card.card_caps(); - let rc = card.reader_caps(); - - let mut tx: Transaction = - openpgp_card_pcsc::start_tx!(card.card(), true)?; - let mut txc = TxClient::new(&mut tx, cc, rc); + let mut txc: TxClient = openpgp_card_pcsc::get_txc!(card, true)?; let open = Open::new(&mut txc)?; println!(" {}", open.application_identifier()?.ident()); diff --git a/card-functionality/src/tests.rs b/card-functionality/src/tests.rs index bb46d06..8eb77b4 100644 --- a/card-functionality/src/tests.rs +++ b/card-functionality/src/tests.rs @@ -681,15 +681,10 @@ pub fn run_test( let mut card_client = card.get_card()?; use anyhow::anyhow; - use pcsc::Transaction; - let card_caps = card_client.card_caps(); - let reader_caps = card_client.reader_caps(); - - let mut tx: Transaction = - openpgp_card_pcsc::start_tx!(card_client.card(), true) - .map_err(|e| anyhow!(e))?; - let mut txc = TxClient::new(&mut tx, card_caps, reader_caps); + let mut txc = openpgp_card_pcsc::get_txc!(card_client, true) + .map_err(|e| anyhow!(e))?; + // let mut txc = TxClient::new(&mut tx, card_caps, reader_caps); t(&mut txc, param) } diff --git a/pcsc/src/lib.rs b/pcsc/src/lib.rs index 05f295e..4e55389 100644 --- a/pcsc/src/lib.rs +++ b/pcsc/src/lib.rs @@ -16,18 +16,23 @@ use openpgp_card::{CardCaps, CardClient, Error, SmartcardError}; const FEATURE_VERIFY_PIN_DIRECT: u8 = 0x06; const FEATURE_MODIFY_PIN_DIRECT: u8 = 0x07; -/// Get a TxClient from a Card +/// Get a TxClient from a PcscCard (this starts a transaction on the card +/// in PcscCard) #[macro_export] -macro_rules! start_tx { +macro_rules! get_txc { ($card:expr, $reselect:expr) => {{ use openpgp_card::{Error, SmartcardError}; use pcsc::{Disposition, Protocols, ShareMode}; - use std::collections::HashMap; + // use std::collections::HashMap; let mut was_reset = false; + let card_caps = $card.card_caps(); + let reader_caps = $card.reader_caps().clone(); + let c = $card.card(); + loop { - let res = $card.transaction(); + let res = c.transaction(); match res { Ok(mut tx) => { @@ -39,7 +44,7 @@ macro_rules! start_tx { ); let mut txc = - TxClient::new(&mut tx, None, HashMap::default()); + TxClient::new(tx, card_caps, reader_caps.clone()); // In contexts where the caller of this macro // expects that the card has already been opened, @@ -50,9 +55,13 @@ macro_rules! start_tx { if $reselect { TxClient::select(&mut txc)?; } + + tx = txc.tx(); } - break Ok(tx); + let txc = TxClient::new(tx, card_caps, reader_caps); + + break Ok(txc); } Err(pcsc::Error::ResetCard) => { // Card was reset, need to reconnect @@ -63,17 +72,17 @@ macro_rules! start_tx { 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), - )) - })?; + c.reconnect( + ShareMode::Shared, + Protocols::ANY, + Disposition::ResetCard, + ) + .map_err(|e| { + Error::Smartcard(SmartcardError::Error(format!( + "Reconnect failed: {:?}", + e + ))) + })?; } log::debug!("start_tx: reconnected."); @@ -113,15 +122,15 @@ pub struct PcscCard { /// (e.g. Microsoft documents that on Windows, they will be closed after /// 5s without a command: /// ) -pub struct TxClient<'a, 'b> { - tx: &'a mut Transaction<'b>, +pub struct TxClient<'b> { + tx: Transaction<'b>, card_caps: Option, // FIXME: manual copy from PcscCard reader_caps: HashMap, // FIXME: manual copy from PcscCard } -impl<'a, 'b> TxClient<'a, 'b> { +impl<'b> TxClient<'b> { pub fn new( - tx: &'a mut Transaction<'b>, + tx: Transaction<'b>, card_caps: Option, reader_caps: HashMap, ) -> Self { @@ -133,7 +142,7 @@ impl<'a, 'b> TxClient<'a, 'b> { } /// Try to select the OpenPGP application on a card - pub fn select(card_client: &'a mut TxClient) -> Result<(), Error> { + pub fn select(card_client: &mut TxClient) -> Result<(), Error> { if ::select(card_client).is_ok() { Ok(()) } else { @@ -192,9 +201,13 @@ impl<'a, 'b> TxClient<'a, 'b> { Err(anyhow!("card_caps is None")) } } + + pub fn tx(self) -> Transaction<'b> { + self.tx + } } -impl CardClient for TxClient<'_, '_> { +impl CardClient for TxClient<'_> { fn transmit( &mut self, cmd: &[u8], @@ -514,9 +527,9 @@ impl PcscCard { { // start transaction log::debug!("1"); - let mut tx: Transaction = start_tx!(card, false)?; + let mut p = PcscCard::new(card); + let mut txc: TxClient = get_txc!(p, false)?; - let mut txc = TxClient::new(&mut tx, None, HashMap::default()); log::debug!("3"); { if let Err(e) = TxClient::select(&mut txc) { @@ -532,7 +545,7 @@ impl PcscCard { // successfully opened the OpenPGP application // -- debug: status -- - drop(txc); + let tx = txc.tx(); let stat = tx.status2_owned().map_err(|e| { Error::Smartcard(SmartcardError::Error(format!( "{:?}", @@ -540,8 +553,7 @@ impl PcscCard { ))) })?; log::debug!("4b card status: {:x?}", stat); - let mut txc = - TxClient::new(&mut tx, None, HashMap::default()); + txc = TxClient::new(tx, None, HashMap::default()); // -- /debug: status -- if let Some(ident) = ident { @@ -579,6 +591,9 @@ impl PcscCard { } } } + + drop(txc); + card = p.card; } if store_card { @@ -633,25 +648,30 @@ impl PcscCard { fn initialize_card(mut self) -> Result { log::debug!("pcsc initialize_card"); - let mut tx: Transaction = start_tx!(self.card, true)?; - let mut txc = - TxClient::new(&mut tx, self.card_caps, self.reader_caps.clone()); + let mut h: HashMap = HashMap::default(); + + let mut txc: TxClient = get_txc!(self, true)?; // Get Features from reader (pinpad verify/modify) if let Ok(feat) = txc.features() { for tlv in feat { log::debug!("Found reader feature {:?}", tlv); - self.reader_caps.insert(tlv.tag().into(), tlv); + h.insert(tlv.tag().into(), tlv); } } // Initalize CardClient (set CardCaps from ARD) ::initialize(&mut txc)?; - self.card_caps = txc.card_caps().cloned(); + let cc = txc.card_caps().cloned(); drop(txc); - drop(tx); + + self.card_caps = cc; + + for (a, b) in h { + self.reader_caps.insert(a, b); + } Ok(self) }