diff --git a/openpgp-card/src/apdu/mod.rs b/openpgp-card/src/apdu/mod.rs index ef633dd..4de8ac6 100644 --- a/openpgp-card/src/apdu/mod.rs +++ b/openpgp-card/src/apdu/mod.rs @@ -11,6 +11,8 @@ use std::convert::TryFrom; use crate::apdu::command::Command; use crate::apdu::response::Response; +use crate::card; +use crate::card_app::CardApp; use crate::errors::{OcErrorStatus, OpenpgpCardError, SmartcardError}; use crate::{CardBase, CardCaps, CardClient, CardClientBox}; @@ -188,6 +190,14 @@ impl PcscClient { Self { card } } + pub fn list_cards() -> Result> { + Ok(card::get_cards() + .map_err(|err| anyhow!(err))? + .into_iter() + .map(PcscClient::new) + .collect()) + } + /// Take a PCSC Card object and try to open the OpenPGP card applet. /// If successful, wrap and return the resulting CardClient as a /// CardBase object (which involves caching the "application related @@ -196,11 +206,11 @@ impl PcscClient { let card_client = PcscClient::new(card); let mut ccb = Box::new(card_client) as CardClientBox; - let select_openpgp = commands::select_openpgp(); - let resp = send_command(&mut ccb, select_openpgp, false, None)?; + let mut ca = CardApp::new(ccb); + let resp = ca.select()?; if resp.is_ok() { - CardBase::open_card(ccb) + CardBase::open_card(ca.take_card()) } else { Err(anyhow!("Couldn't open OpenPGP application").into()) } diff --git a/openpgp-card/src/card_app.rs b/openpgp-card/src/card_app.rs index 85ef4f8..e1a6fbd 100644 --- a/openpgp-card/src/card_app.rs +++ b/openpgp-card/src/card_app.rs @@ -42,6 +42,43 @@ impl CardApp { } } + pub(crate) fn take_card(self) -> CardClientBox { + self.card_client + } + + /// Read capabilities from the card, and set them in the CardApp + pub fn init_caps(mut self, ard: &Tlv) -> Result { + // Determine chaining/extended length support from card + // metadata and cache this information in CardApp (as a + // CardCaps) + + let mut ext_support = false; + let mut chaining_support = false; + + if let Ok(hist) = CardApp::get_historical(&ard) { + if let Some(cc) = hist.get_card_capabilities() { + chaining_support = cc.get_command_chaining(); + ext_support = cc.get_extended_lc_le(); + } + } + + let max_cmd_bytes = if let Ok(Some(eli)) = + CardApp::get_extended_length_information(&ard) + { + eli.max_command_bytes + } else { + 255 + }; + + let caps = CardCaps { + ext_support, + chaining_support, + max_cmd_bytes, + }; + + Ok(self.set_caps(caps)) + } + pub fn set_caps(self, card_caps: CardCaps) -> Self { Self { card_client: self.card_client, @@ -57,6 +94,14 @@ impl CardApp { self.card_caps.as_ref() } + // --- select --- + + /// "Select" the OpenPGP card application + pub fn select(&mut self) -> Result { + let select_openpgp = commands::select_openpgp(); + apdu::send_command(&mut self.card_client, select_openpgp, false, None) + } + // --- application data --- /// Load "application related data". diff --git a/openpgp-card/src/lib.rs b/openpgp-card/src/lib.rs index 65dfbef..3224d64 100644 --- a/openpgp-card/src/lib.rs +++ b/openpgp-card/src/lib.rs @@ -18,7 +18,7 @@ use crate::card_app::CardApp; use crate::errors::{OpenpgpCardError, SmartcardError}; use std::ops::{Deref, DerefMut}; -mod apdu; +pub mod apdu; mod card; pub mod card_app; pub mod errors; @@ -145,7 +145,7 @@ pub enum DecryptMe<'a> { ECDH(&'a [u8]), } -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum Sex { NotKnown, Male, @@ -314,36 +314,10 @@ impl CardBase { pub fn open_card(ccb: CardClientBox) -> Result { // read and cache "application related data" let mut card_app = CardApp::new(ccb); + let ard = card_app.get_app_data()?; - // Determine chaining/extended length support from card - // metadata and cache this information in CardApp (as a - // CardCaps) - - let mut ext_support = false; - let mut chaining_support = false; - - if let Ok(hist) = CardApp::get_historical(&ard) { - if let Some(cc) = hist.get_card_capabilities() { - chaining_support = cc.get_command_chaining(); - ext_support = cc.get_extended_lc_le(); - } - } - - let max_cmd_bytes = if let Ok(Some(eli)) = - CardApp::get_extended_length_information(&ard) - { - eli.max_command_bytes - } else { - 255 - }; - - let caps = CardCaps { - ext_support, - chaining_support, - max_cmd_bytes, - }; - let card_app = card_app.set_caps(caps); + card_app = card_app.init_caps(&ard)?; Ok(Self { card_app, ard }) }