Restructure cards() and open_by_ident(); Add debug logging
This commit is contained in:
parent
2c3bc492ab
commit
0baf36df67
1 changed files with 136 additions and 88 deletions
210
pcsc/src/lib.rs
210
pcsc/src/lib.rs
|
@ -25,45 +25,157 @@ pub struct PcscClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PcscClient {
|
impl PcscClient {
|
||||||
/// Return all cards on which the OpenPGP application could be selected.
|
/// A list of "raw" opened PCSC Cards (without selecting the OpenPGP card
|
||||||
///
|
/// application)
|
||||||
/// Each card has the OpenPGP application selected, CardCaps have been
|
fn raw_pcsc_cards() -> Result<Vec<Card>, SmartcardError> {
|
||||||
/// initialized.
|
let ctx = match Context::establish(Scope::User) {
|
||||||
pub fn cards() -> Result<Vec<CardApp>> {
|
Ok(ctx) => ctx,
|
||||||
|
Err(err) => {
|
||||||
|
log::debug!("Context::establish failed: {:?}", err);
|
||||||
|
return Err(SmartcardError::ContextError(err.to_string()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// List available readers.
|
||||||
|
let mut readers_buf = [0; 2048];
|
||||||
|
let readers = match ctx.list_readers(&mut readers_buf) {
|
||||||
|
Ok(readers) => readers,
|
||||||
|
Err(err) => {
|
||||||
|
log::debug!("list_readers failed: {:?}", err);
|
||||||
|
return Err(SmartcardError::ReaderError(err.to_string()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
log::debug!("readers: {:?}", readers);
|
||||||
|
|
||||||
|
let mut found_reader = false;
|
||||||
|
|
||||||
|
let mut cards = vec![];
|
||||||
|
|
||||||
|
// Find a reader with a SmartCard.
|
||||||
|
for reader in readers {
|
||||||
|
// We've seen at least one smartcard reader
|
||||||
|
found_reader = true;
|
||||||
|
|
||||||
|
log::debug!("Checking reader: {:?}", reader);
|
||||||
|
|
||||||
|
// Try connecting to card in this reader
|
||||||
|
let card =
|
||||||
|
match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) {
|
||||||
|
Ok(card) => card,
|
||||||
|
Err(pcsc::Error::NoSmartcard) => {
|
||||||
|
log::debug!("No Smartcard");
|
||||||
|
|
||||||
|
continue; // try next reader
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!(
|
||||||
|
"Error connecting to card in reader: {:x?}",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
log::debug!("Found card");
|
||||||
|
|
||||||
|
cards.push(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found_reader {
|
||||||
|
Err(SmartcardError::NoReaderFoundError)
|
||||||
|
} else {
|
||||||
|
Ok(cards)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// All PCSC cards, wrapped as PcscClient
|
||||||
|
fn unopened_cards() -> Result<Vec<PcscClient>> {
|
||||||
|
Ok(Self::raw_pcsc_cards()
|
||||||
|
.map_err(|err| anyhow!(err))?
|
||||||
|
.into_iter()
|
||||||
|
.map(PcscClient::new)
|
||||||
|
.collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cards_filter(ident: Option<&str>) -> Result<Vec<CardApp>> {
|
||||||
let mut cards = vec![];
|
let mut cards = vec![];
|
||||||
|
|
||||||
for mut card in Self::unopened_cards()? {
|
for mut card in Self::unopened_cards()? {
|
||||||
if Self::select(&mut card).is_ok() {
|
log::debug!("cards_filter: next card");
|
||||||
if let Ok(ca) = card.into_card_app() {
|
|
||||||
|
// FIXME: start transaction
|
||||||
|
// let tx = card.card.transaction()?;
|
||||||
|
|
||||||
|
if let Err(e) = Self::select(&mut card) {
|
||||||
|
log::debug!("cards_filter: error during select: {:?}", e);
|
||||||
|
} else {
|
||||||
|
if let Ok(mut ca) = card.into_card_app() {
|
||||||
|
if let Some(ident) = ident {
|
||||||
|
let ard = ca.application_related_data()?;
|
||||||
|
let aid = ard.application_id()?;
|
||||||
|
|
||||||
|
if aid.ident() == ident.to_ascii_uppercase() {
|
||||||
|
// FIXME: handle multiple cards with matching ident
|
||||||
|
log::debug!(
|
||||||
|
"open_by_ident: Opened and selected {:?}",
|
||||||
|
ident
|
||||||
|
);
|
||||||
|
|
||||||
|
cards.push(ca);
|
||||||
|
} else {
|
||||||
|
log::debug!(
|
||||||
|
"open_by_ident: Found, but won't use {:?}",
|
||||||
|
aid.ident()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// return all cards
|
||||||
cards.push(ca);
|
cards.push(ca);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: end transaction
|
||||||
|
// tx.end(Disposition::LeaveCard).map_err(|(_, e)| {
|
||||||
|
// Error::Smartcard(SmartcardError::Error(
|
||||||
|
// format!("PCSC Transaction::end failed: {:?}", e)
|
||||||
|
// ))
|
||||||
|
// })?;
|
||||||
|
}
|
||||||
|
|
||||||
|
log::debug!("cards_filter: found {} cards", cards.len());
|
||||||
|
|
||||||
Ok(cards)
|
Ok(cards)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return all cards on which the OpenPGP application could be selected.
|
||||||
|
///
|
||||||
|
/// Each card has the OpenPGP application selected, CardCaps have been
|
||||||
|
/// initialized.
|
||||||
|
pub fn cards() -> Result<Vec<CardApp>> {
|
||||||
|
Self::cards_filter(None)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the OpenPGP card that matches `ident`, if it is available.
|
/// Returns the OpenPGP card that matches `ident`, if it is available.
|
||||||
/// A fully initialized CardApp is returned: the OpenPGP application has
|
/// A fully initialized CardApp is returned: the OpenPGP application has
|
||||||
/// been selected, CardCaps have been set.
|
/// been selected, CardCaps have been set.
|
||||||
pub fn open_by_ident(ident: &str) -> Result<CardApp, Error> {
|
pub fn open_by_ident(ident: &str) -> Result<CardApp, Error> {
|
||||||
for mut card in Self::unopened_cards()? {
|
log::debug!("open_by_ident for {:?}", ident);
|
||||||
if Self::select(&mut card).is_ok() {
|
|
||||||
let mut ca = card.into_card_app()?;
|
|
||||||
|
|
||||||
let ard = ca.application_related_data()?;
|
let mut cards = Self::cards_filter(Some(ident))?;
|
||||||
let aid = ard.application_id()?;
|
|
||||||
|
|
||||||
if aid.ident() == ident.to_ascii_uppercase() {
|
if !cards.is_empty() {
|
||||||
return Ok(ca);
|
// FIXME: handle >1 cards found
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Ok(cards.pop().unwrap())
|
||||||
|
} else {
|
||||||
Err(Error::Smartcard(SmartcardError::CardNotFound(
|
Err(Error::Smartcard(SmartcardError::CardNotFound(
|
||||||
ident.to_string(),
|
ident.to_string(),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn new(card: Card) -> Self {
|
fn new(card: Card) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -88,70 +200,6 @@ impl PcscClient {
|
||||||
CardApp::initialize(Box::new(self))
|
CardApp::initialize(Box::new(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A list of "raw" opened PCSC Cards (without selecting the OpenPGP card
|
|
||||||
/// application)
|
|
||||||
fn raw_pcsc_cards() -> Result<Vec<Card>, SmartcardError> {
|
|
||||||
let ctx = match Context::establish(Scope::User) {
|
|
||||||
Ok(ctx) => ctx,
|
|
||||||
Err(err) => {
|
|
||||||
return Err(SmartcardError::ContextError(err.to_string()))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// List available readers.
|
|
||||||
let mut readers_buf = [0; 2048];
|
|
||||||
let readers = match ctx.list_readers(&mut readers_buf) {
|
|
||||||
Ok(readers) => readers,
|
|
||||||
Err(err) => {
|
|
||||||
return Err(SmartcardError::ReaderError(err.to_string()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut found_reader = false;
|
|
||||||
|
|
||||||
let mut cards = vec![];
|
|
||||||
|
|
||||||
// Find a reader with a SmartCard.
|
|
||||||
for reader in readers {
|
|
||||||
// We've seen at least one smartcard reader
|
|
||||||
found_reader = true;
|
|
||||||
|
|
||||||
// Try connecting to card in this reader
|
|
||||||
let card =
|
|
||||||
match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) {
|
|
||||||
Ok(card) => card,
|
|
||||||
Err(pcsc::Error::NoSmartcard) => {
|
|
||||||
continue; // try next reader
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
log::warn!(
|
|
||||||
"Error connecting to card in reader: {:x?}",
|
|
||||||
err
|
|
||||||
);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
cards.push(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found_reader {
|
|
||||||
Err(SmartcardError::NoReaderFoundError)
|
|
||||||
} else {
|
|
||||||
Ok(cards)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// All PCSC cards, wrapped as PcscClient
|
|
||||||
fn unopened_cards() -> Result<Vec<PcscClient>> {
|
|
||||||
Ok(Self::raw_pcsc_cards()
|
|
||||||
.map_err(|err| anyhow!(err))?
|
|
||||||
.into_iter()
|
|
||||||
.map(PcscClient::new)
|
|
||||||
.collect())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Try to select the OpenPGP application on a card
|
/// Try to select the OpenPGP application on a card
|
||||||
fn select(card_client: &mut PcscClient) -> Result<(), Error> {
|
fn select(card_client: &mut PcscClient) -> Result<(), Error> {
|
||||||
if <dyn CardClient>::select(card_client).is_ok() {
|
if <dyn CardClient>::select(card_client).is_ok() {
|
||||||
|
|
Loading…
Reference in a new issue