use card_backend_pcsc::PcscBackend;
use openpgp_card::Card;
use secrecy::SecretString;
use super::types::{CardError, CardInfo};
use crate::error::{Error, Result};
pub fn is_card_connected() -> bool {
match PcscBackend::cards(None) {
Ok(mut cards) => cards.next().is_some(),
Err(_) => false,
}
}
fn get_card_backend() -> Result<PcscBackend> {
let mut cards = PcscBackend::cards(None)
.map_err(|e| Error::Card(CardError::CommunicationError(e.to_string())))?;
cards.next()
.ok_or(Error::Card(CardError::NotConnected))?
.map_err(|e| Error::Card(CardError::CommunicationError(e.to_string())))
}
fn pin_to_secret(pin: &[u8]) -> Result<SecretString> {
let pin_str = std::str::from_utf8(pin)
.map_err(|_| Error::Card(CardError::InvalidData("PIN must be valid UTF-8".to_string())))?;
Ok(SecretString::new(pin_str.to_string()))
}
pub fn get_card_details() -> Result<CardInfo> {
let backend = get_card_backend()?;
let mut card = Card::new(backend)
.map_err(|e| Error::Card(CardError::from(e)))?;
let mut tx = card.transaction()
.map_err(|e| Error::Card(CardError::from(e)))?;
let mut info = CardInfo::default();
if let Ok(aid) = tx.application_identifier() {
info.serial_number = format!("{:08X}", aid.serial());
info.manufacturer = Some(format!("{:04X}", aid.manufacturer()));
}
if let Ok(fps) = tx.fingerprints() {
if let Some(fp) = fps.signature() {
info.signature_fingerprint = Some(hex::encode(fp.as_bytes()));
}
if let Some(fp) = fps.decryption() {
info.encryption_fingerprint = Some(hex::encode(fp.as_bytes()));
}
if let Some(fp) = fps.authentication() {
info.authentication_fingerprint = Some(hex::encode(fp.as_bytes()));
}
}
if let Ok(status) = tx.pw_status_bytes() {
info.pin_retry_counter = status.err_count_pw1();
info.reset_code_retry_counter = status.err_count_rc();
info.admin_pin_retry_counter = status.err_count_pw3();
}
if let Ok(name) = tx.cardholder_name() {
if !name.is_empty() {
info.cardholder_name = Some(name);
}
}
if let Ok(url) = tx.url() {
if !url.is_empty() {
info.public_key_url = Some(url);
}
}
Ok(info)
}
pub fn get_card_version() -> Result<String> {
let backend = get_card_backend()?;
let mut card = Card::new(backend)
.map_err(|e| Error::Card(CardError::from(e)))?;
let tx = card.transaction()
.map_err(|e| Error::Card(CardError::from(e)))?;
let aid = tx.application_identifier()
.map_err(|e| Error::Card(CardError::from(e)))?;
let version = aid.version();
let major = version >> 8;
let minor = version & 0xFF;
Ok(format!("{}.{}", major, minor))
}
pub fn get_card_serial() -> Result<String> {
let backend = get_card_backend()?;
let mut card = Card::new(backend)
.map_err(|e| Error::Card(CardError::from(e)))?;
let tx = card.transaction()
.map_err(|e| Error::Card(CardError::from(e)))?;
let aid = tx.application_identifier()
.map_err(|e| Error::Card(CardError::from(e)))?;
Ok(format!("{:08X}", aid.serial()))
}
pub fn verify_user_pin(pin: &[u8]) -> Result<bool> {
let backend = get_card_backend()?;
let mut card = Card::new(backend)
.map_err(|e| Error::Card(CardError::from(e)))?;
let mut tx = card.transaction()
.map_err(|e| Error::Card(CardError::from(e)))?;
let secret_pin = pin_to_secret(pin)?;
tx.verify_user_pin(secret_pin)
.map_err(|e| Error::Card(CardError::from(e)))?;
Ok(true)
}
pub fn verify_admin_pin(pin: &[u8]) -> Result<bool> {
let backend = get_card_backend()?;
let mut card = Card::new(backend)
.map_err(|e| Error::Card(CardError::from(e)))?;
let mut tx = card.transaction()
.map_err(|e| Error::Card(CardError::from(e)))?;
let secret_pin = pin_to_secret(pin)?;
tx.verify_admin_pin(secret_pin)
.map_err(|e| Error::Card(CardError::from(e)))?;
Ok(true)
}
pub fn get_pin_retry_counters() -> Result<(u8, u8, u8)> {
let backend = get_card_backend()?;
let mut card = Card::new(backend)
.map_err(|e| Error::Card(CardError::from(e)))?;
let mut tx = card.transaction()
.map_err(|e| Error::Card(CardError::from(e)))?;
let status = tx.pw_status_bytes()
.map_err(|e| Error::Card(CardError::from(e)))?;
Ok((
status.err_count_pw1(),
status.err_count_rc(),
status.err_count_pw3(),
))
}
pub fn reset_card() -> Result<()> {
let backend = get_card_backend()?;
let mut card = Card::new(backend)
.map_err(|e| Error::Card(CardError::from(e)))?;
let mut tx = card.transaction()
.map_err(|e| Error::Card(CardError::from(e)))?;
tx.factory_reset()
.map_err(|e| Error::Card(CardError::from(e)))?;
Ok(())
}
pub fn change_user_pin(old_pin: &[u8], new_pin: &[u8]) -> Result<()> {
let backend = get_card_backend()?;
let mut card = Card::new(backend)
.map_err(|e| Error::Card(CardError::from(e)))?;
let mut tx = card.transaction()
.map_err(|e| Error::Card(CardError::from(e)))?;
let old_secret = pin_to_secret(old_pin)?;
let new_secret = pin_to_secret(new_pin)?;
tx.change_user_pin(old_secret, new_secret)
.map_err(|e| Error::Card(CardError::from(e)))?;
Ok(())
}
pub fn change_admin_pin(old_pin: &[u8], new_pin: &[u8]) -> Result<()> {
let backend = get_card_backend()?;
let mut card = Card::new(backend)
.map_err(|e| Error::Card(CardError::from(e)))?;
let mut tx = card.transaction()
.map_err(|e| Error::Card(CardError::from(e)))?;
let old_secret = pin_to_secret(old_pin)?;
let new_secret = pin_to_secret(new_pin)?;
tx.change_admin_pin(old_secret, new_secret)
.map_err(|e| Error::Card(CardError::from(e)))?;
Ok(())
}
#[cfg(test)]
mod tests {
}