Don't implement CardClient for PcscClient (users should always use transactions)
This commit is contained in:
parent
2480745088
commit
431da53b28
2 changed files with 275 additions and 259 deletions
|
@ -2,15 +2,22 @@
|
||||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use pcsc::Transaction;
|
||||||
|
|
||||||
use openpgp_card_pcsc::PcscClient;
|
use openpgp_card_pcsc::{PcscClient, PcscTxClient};
|
||||||
use openpgp_card_sequoia::card::Open;
|
use openpgp_card_sequoia::card::Open;
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
println!("The following OpenPGP cards are connected to your system:");
|
println!("The following OpenPGP cards are connected to your system:");
|
||||||
|
|
||||||
for mut ca in PcscClient::cards()? {
|
for mut card in PcscClient::cards()? {
|
||||||
let open = Open::new(&mut ca)?;
|
let cc = card.card_caps();
|
||||||
|
|
||||||
|
let mut tx: Transaction =
|
||||||
|
openpgp_card_pcsc::start_tx!(card.card(), true)?;
|
||||||
|
let mut txc = PcscTxClient::new(&mut tx, cc);
|
||||||
|
|
||||||
|
let open = Open::new(&mut txc)?;
|
||||||
println!(" {}", open.application_identifier()?.ident());
|
println!(" {}", open.application_identifier()?.ident());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
521
pcsc/src/lib.rs
521
pcsc/src/lib.rs
|
@ -20,7 +20,9 @@ const FEATURE_MODIFY_PIN_DIRECT: u8 = 0x07;
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! start_tx {
|
macro_rules! start_tx {
|
||||||
($card:expr, $reselect:expr) => {{
|
($card:expr, $reselect:expr) => {{
|
||||||
use pcsc::{Disposition, Protocols, ShareMode};
|
use anyhow::anyhow;
|
||||||
|
use openpgp_card::{Error, SmartcardError};
|
||||||
|
use pcsc::{Disposition, Protocols, ShareMode, Transaction};
|
||||||
|
|
||||||
let mut was_reset = false;
|
let mut was_reset = false;
|
||||||
|
|
||||||
|
@ -101,9 +103,7 @@ impl<'a, 'b> PcscTxClient<'a, 'b> {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
PcscTxClient { tx, card_caps }
|
PcscTxClient { tx, card_caps }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> PcscTxClient<'a, 'b> {
|
|
||||||
/// Try to select the OpenPGP application on a card
|
/// Try to select the OpenPGP application on a card
|
||||||
pub fn select(card_client: &'a mut PcscTxClient) -> Result<(), Error> {
|
pub fn select(card_client: &'a mut PcscTxClient) -> Result<(), Error> {
|
||||||
if <dyn CardClient>::select(card_client).is_ok() {
|
if <dyn CardClient>::select(card_client).is_ok() {
|
||||||
|
@ -124,6 +124,25 @@ impl<'a, 'b> PcscTxClient<'a, 'b> {
|
||||||
)))
|
)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// GET_FEATURE_REQUEST
|
||||||
|
/// (see http://pcscworkgroup.com/Download/Specifications/pcsc10_v2.02.09.pdf)
|
||||||
|
fn features(&mut self) -> Result<Vec<Tlv>, Error> {
|
||||||
|
let mut recv = vec![0; 1024];
|
||||||
|
|
||||||
|
let cm_ioctl_get_feature_request = pcsc::ctl_code(3400);
|
||||||
|
let res = self
|
||||||
|
.tx
|
||||||
|
.control(cm_ioctl_get_feature_request, &[], &mut recv)
|
||||||
|
.map_err(|e| {
|
||||||
|
Error::Smartcard(SmartcardError::Error(format!(
|
||||||
|
"GET_FEATURE_REQUEST control call failed: {:?}",
|
||||||
|
e
|
||||||
|
)))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(Tlv::parse_all(res))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CardClient for PcscTxClient<'_, '_> {
|
impl CardClient for PcscTxClient<'_, '_> {
|
||||||
|
@ -380,13 +399,17 @@ impl PcscClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make an initialized CardApp from a PcscClient.
|
/// Make an initialized CardApp from a PcscClient:
|
||||||
/// Obtain and store feature lists from reader (pinpad functionality).
|
/// - Obtain and store feature lists from reader (pinpad functionality).
|
||||||
|
/// - Get ARD from card, set CardCaps based on ARD.
|
||||||
fn initialize_card(mut self) -> Result<Self> {
|
fn initialize_card(mut self) -> Result<Self> {
|
||||||
log::debug!("pcsc initialize_card");
|
log::debug!("pcsc initialize_card");
|
||||||
|
|
||||||
|
let mut tx: Transaction = start_tx!(self.card, true)?;
|
||||||
|
let mut txc = PcscTxClient::new(&mut tx, self.card_caps);
|
||||||
|
|
||||||
// Get Features from reader (pinpad verify/modify)
|
// Get Features from reader (pinpad verify/modify)
|
||||||
if let Ok(feat) = self.features() {
|
if let Ok(feat) = txc.features() {
|
||||||
for tlv in feat {
|
for tlv in feat {
|
||||||
log::debug!("Found reader feature {:?}", tlv);
|
log::debug!("Found reader feature {:?}", tlv);
|
||||||
self.reader_caps.insert(tlv.tag().into(), tlv);
|
self.reader_caps.insert(tlv.tag().into(), tlv);
|
||||||
|
@ -394,7 +417,12 @@ impl PcscClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initalize CardClient (set CardCaps from ARD)
|
// Initalize CardClient (set CardCaps from ARD)
|
||||||
<dyn CardClient>::initialize(&mut self)?;
|
<dyn CardClient>::initialize(&mut txc)?;
|
||||||
|
|
||||||
|
self.card_caps = txc.card_caps().cloned();
|
||||||
|
|
||||||
|
drop(txc);
|
||||||
|
drop(tx);
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
@ -420,257 +448,238 @@ impl PcscClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// GET_FEATURE_REQUEST
|
|
||||||
/// (see http://pcscworkgroup.com/Download/Specifications/pcsc10_v2.02.09.pdf)
|
|
||||||
fn features(&mut self) -> Result<Vec<Tlv>, Error> {
|
|
||||||
let mut recv = vec![0; 1024];
|
|
||||||
|
|
||||||
let cm_ioctl_get_feature_request = pcsc::ctl_code(3400);
|
|
||||||
let res = self
|
|
||||||
.card
|
|
||||||
.control(cm_ioctl_get_feature_request, &[], &mut recv)
|
|
||||||
.map_err(|e| {
|
|
||||||
Error::Smartcard(SmartcardError::Error(format!(
|
|
||||||
"GET_FEATURE_REQUEST control call failed: {:?}",
|
|
||||||
e
|
|
||||||
)))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(Tlv::parse_all(res))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn card_caps(&self) -> Option<CardCaps> {
|
pub fn card_caps(&self) -> Option<CardCaps> {
|
||||||
self.card_caps
|
self.card_caps
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CardClient for PcscClient {
|
// impl CardClient for PcscClient {
|
||||||
fn transmit(
|
// fn transmit(
|
||||||
&mut self,
|
// &mut self,
|
||||||
cmd: &[u8],
|
// cmd: &[u8],
|
||||||
buf_size: usize,
|
// buf_size: usize,
|
||||||
) -> Result<Vec<u8>, Error> {
|
// ) -> Result<Vec<u8>, Error> {
|
||||||
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: Transaction = start_tx!(self.card, true)?;
|
// let mut tx: Transaction = start_tx!(self.card, true)?;
|
||||||
|
//
|
||||||
log::debug!("PcscClient transmit 2");
|
// log::debug!("PcscClient transmit 2");
|
||||||
let mut txc = PcscTxClient::new(&mut tx, self.card_caps);
|
// let mut txc = PcscTxClient::new(&mut tx, self.card_caps);
|
||||||
log::debug!("PcscClient transmit 3 (got TxClient!)");
|
// log::debug!("PcscClient transmit 3 (got TxClient!)");
|
||||||
|
//
|
||||||
let res = txc.transmit(cmd, buf_size);
|
// let res = txc.transmit(cmd, buf_size);
|
||||||
|
//
|
||||||
log::debug!("PcscClient transmit res {:x?}", res);
|
// log::debug!("PcscClient transmit res {:x?}", res);
|
||||||
|
//
|
||||||
res
|
// res
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
fn init_card_caps(&mut self, caps: CardCaps) {
|
// fn init_card_caps(&mut self, caps: CardCaps) {
|
||||||
self.card_caps = Some(caps);
|
// self.card_caps = Some(caps);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
fn card_caps(&self) -> Option<&CardCaps> {
|
// fn card_caps(&self) -> Option<&CardCaps> {
|
||||||
self.card_caps.as_ref()
|
// self.card_caps.as_ref()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
fn feature_pinpad_verify(&self) -> bool {
|
// fn feature_pinpad_verify(&self) -> bool {
|
||||||
self.reader_caps.contains_key(&FEATURE_VERIFY_PIN_DIRECT)
|
// self.reader_caps.contains_key(&FEATURE_VERIFY_PIN_DIRECT)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
fn feature_pinpad_modify(&self) -> bool {
|
// fn feature_pinpad_modify(&self) -> bool {
|
||||||
self.reader_caps.contains_key(&FEATURE_MODIFY_PIN_DIRECT)
|
// self.reader_caps.contains_key(&FEATURE_MODIFY_PIN_DIRECT)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
fn pinpad_verify(&mut self, pin_id: u8) -> Result<Vec<u8>> {
|
// fn pinpad_verify(&mut self, pin_id: u8) -> Result<Vec<u8>> {
|
||||||
let pin_min_size = self.min_pin_len(pin_id)?;
|
// let pin_min_size = self.min_pin_len(pin_id)?;
|
||||||
let pin_max_size = self.max_pin_len(pin_id)?;
|
// let pin_max_size = self.max_pin_len(pin_id)?;
|
||||||
|
//
|
||||||
// Default to varlen, for now.
|
// // Default to varlen, for now.
|
||||||
// (NOTE: Some readers don't support varlen, and need explicit length
|
// // (NOTE: Some readers don't support varlen, and need explicit length
|
||||||
// information. Also see https://wiki.gnupg.org/CardReader/PinpadInput)
|
// // information. Also see https://wiki.gnupg.org/CardReader/PinpadInput)
|
||||||
let fixedlen: u8 = 0;
|
// let fixedlen: u8 = 0;
|
||||||
|
//
|
||||||
// APDU: 00 20 00 pin_id <len> (ff)*
|
// // APDU: 00 20 00 pin_id <len> (ff)*
|
||||||
let mut ab_data = vec![
|
// let mut ab_data = vec![
|
||||||
0x00, /* CLA */
|
// 0x00, /* CLA */
|
||||||
0x20, /* INS: VERIFY */
|
// 0x20, /* INS: VERIFY */
|
||||||
0x00, /* P1 */
|
// 0x00, /* P1 */
|
||||||
pin_id, /* P2 */
|
// pin_id, /* P2 */
|
||||||
fixedlen, /* Lc: 'fixedlen' data bytes */
|
// fixedlen, /* Lc: 'fixedlen' data bytes */
|
||||||
];
|
// ];
|
||||||
ab_data.extend([0xff].repeat(fixedlen as usize));
|
// ab_data.extend([0xff].repeat(fixedlen as usize));
|
||||||
|
//
|
||||||
// PC/SC v2.02.05 Part 10 PIN verification data structure
|
// // PC/SC v2.02.05 Part 10 PIN verification data structure
|
||||||
let mut send: Vec<u8> = vec![
|
// let mut send: Vec<u8> = vec![
|
||||||
// 0 bTimeOut BYTE timeout in seconds (00 means use default
|
// // 0 bTimeOut BYTE timeout in seconds (00 means use default
|
||||||
// timeout)
|
// // timeout)
|
||||||
0x00,
|
// 0x00,
|
||||||
// 1 bTimeOut2 BYTE timeout in seconds after first key stroke
|
// // 1 bTimeOut2 BYTE timeout in seconds after first key stroke
|
||||||
0x00,
|
// 0x00,
|
||||||
// 2 bmFormatString BYTE formatting options USB_CCID_PIN_FORMAT_xxx
|
// // 2 bmFormatString BYTE formatting options USB_CCID_PIN_FORMAT_xxx
|
||||||
0x82,
|
// 0x82,
|
||||||
// 3 bmPINBlockString BYTE
|
// // 3 bmPINBlockString BYTE
|
||||||
// bits 7-4 bit size of PIN length in APDU
|
// // bits 7-4 bit size of PIN length in APDU
|
||||||
// bits 3-0 PIN block size in bytes after justification and formatting
|
// // bits 3-0 PIN block size in bytes after justification and formatting
|
||||||
fixedlen,
|
// fixedlen,
|
||||||
// 4 bmPINLengthFormat BYTE
|
// // 4 bmPINLengthFormat BYTE
|
||||||
// bits 7-5 RFU, bit 4 set if system units are bytes clear if
|
// // bits 7-5 RFU, bit 4 set if system units are bytes clear if
|
||||||
// system units are bits,
|
// // system units are bits,
|
||||||
// bits 3-0 PIN length position in system units
|
// // bits 3-0 PIN length position in system units
|
||||||
0x00,
|
// 0x00,
|
||||||
// 5 wPINMaxExtraDigit USHORT XXYY, where XX is minimum PIN size
|
// // 5 wPINMaxExtraDigit USHORT XXYY, where XX is minimum PIN size
|
||||||
// in digits, YY is maximum
|
// // in digits, YY is maximum
|
||||||
pin_max_size,
|
// pin_max_size,
|
||||||
pin_min_size,
|
// pin_min_size,
|
||||||
// 7 bEntryValidationCondition BYTE Conditions under which PIN
|
// // 7 bEntryValidationCondition BYTE Conditions under which PIN
|
||||||
// entry should be considered complete.
|
// // entry should be considered complete.
|
||||||
//
|
// //
|
||||||
// table for bEntryValidationCondition:
|
// // table for bEntryValidationCondition:
|
||||||
// 0x01: Max size reached
|
// // 0x01: Max size reached
|
||||||
// 0x02: Validation key pressed
|
// // 0x02: Validation key pressed
|
||||||
// 0x04: Timeout occurred
|
// // 0x04: Timeout occurred
|
||||||
0x07,
|
// 0x07,
|
||||||
// 8 bNumberMessage BYTE Number of messages to display for PIN
|
// // 8 bNumberMessage BYTE Number of messages to display for PIN
|
||||||
// verification
|
// // verification
|
||||||
0x01,
|
// 0x01,
|
||||||
// 9 wLangIdU SHORT Language for messages
|
// // 9 wLangIdU SHORT Language for messages
|
||||||
0x04,
|
// 0x04,
|
||||||
0x09, // US english
|
// 0x09, // US english
|
||||||
// 11 bMsgIndex BYTE Message index (should be 00)
|
// // 11 bMsgIndex BYTE Message index (should be 00)
|
||||||
0x00,
|
// 0x00,
|
||||||
// 12 bTeoPrologue BYTE[3] T=1 I-block prologue field to use (fill with 00)
|
// // 12 bTeoPrologue BYTE[3] T=1 I-block prologue field to use (fill with 00)
|
||||||
0x00,
|
// 0x00,
|
||||||
0x00,
|
// 0x00,
|
||||||
0x00,
|
// 0x00,
|
||||||
];
|
// ];
|
||||||
|
//
|
||||||
// 15 ulDataLength ULONG length of Data to be sent to the ICC
|
// // 15 ulDataLength ULONG length of Data to be sent to the ICC
|
||||||
send.extend(&(ab_data.len() as u32).to_le_bytes());
|
// send.extend(&(ab_data.len() as u32).to_le_bytes());
|
||||||
|
//
|
||||||
// 19 abData BYTE[] Data to send to the ICC
|
// // 19 abData BYTE[] Data to send to the ICC
|
||||||
send.extend(ab_data);
|
// send.extend(ab_data);
|
||||||
|
//
|
||||||
log::debug!("pcsc pinpad_verify send: {:x?}", send);
|
// log::debug!("pcsc pinpad_verify send: {:x?}", send);
|
||||||
|
//
|
||||||
let mut recv = vec![0xAA; 256];
|
// let mut recv = vec![0xAA; 256];
|
||||||
|
//
|
||||||
let verify_ioctl: [u8; 4] = self
|
// let verify_ioctl: [u8; 4] = self
|
||||||
.reader_caps
|
// .reader_caps
|
||||||
.get(&FEATURE_VERIFY_PIN_DIRECT)
|
// .get(&FEATURE_VERIFY_PIN_DIRECT)
|
||||||
.ok_or_else(|| anyhow!("no reader_capability"))?
|
// .ok_or_else(|| anyhow!("no reader_capability"))?
|
||||||
.value()
|
// .value()
|
||||||
.try_into()?;
|
// .try_into()?;
|
||||||
|
//
|
||||||
let res = self.card.control(
|
// let res = self.card.control(
|
||||||
u32::from_be_bytes(verify_ioctl).into(),
|
// u32::from_be_bytes(verify_ioctl).into(),
|
||||||
&send,
|
// &send,
|
||||||
&mut recv,
|
// &mut recv,
|
||||||
)?;
|
// )?;
|
||||||
|
//
|
||||||
log::debug!(" <- pcsc pinpad_verify result: {:x?}", res);
|
// log::debug!(" <- pcsc pinpad_verify result: {:x?}", res);
|
||||||
|
//
|
||||||
Ok(res.to_vec())
|
// Ok(res.to_vec())
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
fn pinpad_modify(&mut self, pin_id: u8) -> Result<Vec<u8>> {
|
// fn pinpad_modify(&mut self, pin_id: u8) -> Result<Vec<u8>> {
|
||||||
let pin_min_size = self.min_pin_len(pin_id)?;
|
// let pin_min_size = self.min_pin_len(pin_id)?;
|
||||||
let pin_max_size = self.max_pin_len(pin_id)?;
|
// let pin_max_size = self.max_pin_len(pin_id)?;
|
||||||
|
//
|
||||||
// Default to varlen, for now.
|
// // Default to varlen, for now.
|
||||||
// (NOTE: Some readers don't support varlen, and need explicit length
|
// // (NOTE: Some readers don't support varlen, and need explicit length
|
||||||
// information. Also see https://wiki.gnupg.org/CardReader/PinpadInput)
|
// // information. Also see https://wiki.gnupg.org/CardReader/PinpadInput)
|
||||||
let fixedlen: u8 = 0;
|
// let fixedlen: u8 = 0;
|
||||||
|
//
|
||||||
// APDU: 00 24 00 pin_id <len> [(ff)* x2]
|
// // APDU: 00 24 00 pin_id <len> [(ff)* x2]
|
||||||
let mut ab_data = vec![
|
// let mut ab_data = vec![
|
||||||
0x00, /* CLA */
|
// 0x00, /* CLA */
|
||||||
0x24, /* INS: CHANGE_REFERENCE_DATA */
|
// 0x24, /* INS: CHANGE_REFERENCE_DATA */
|
||||||
0x00, /* P1 */
|
// 0x00, /* P1 */
|
||||||
pin_id, /* P2 */
|
// pin_id, /* P2 */
|
||||||
fixedlen * 2, /* Lc: 'fixedlen' data bytes */
|
// fixedlen * 2, /* Lc: 'fixedlen' data bytes */
|
||||||
];
|
// ];
|
||||||
ab_data.extend([0xff].repeat(fixedlen as usize * 2));
|
// ab_data.extend([0xff].repeat(fixedlen as usize * 2));
|
||||||
|
//
|
||||||
// PC/SC v2.02.05 Part 10 PIN modification data structure
|
// // PC/SC v2.02.05 Part 10 PIN modification data structure
|
||||||
let mut send: Vec<u8> = vec![
|
// let mut send: Vec<u8> = vec![
|
||||||
// 0 bTimeOut BYTE timeout in seconds (00 means use default
|
// // 0 bTimeOut BYTE timeout in seconds (00 means use default
|
||||||
// timeout)
|
// // timeout)
|
||||||
0x00,
|
// 0x00,
|
||||||
// 1 bTimeOut2 BYTE timeout in seconds after first key stroke
|
// // 1 bTimeOut2 BYTE timeout in seconds after first key stroke
|
||||||
0x00,
|
// 0x00,
|
||||||
// 2 bmFormatString BYTE formatting options USB_CCID_PIN_FORMAT_xxx
|
// // 2 bmFormatString BYTE formatting options USB_CCID_PIN_FORMAT_xxx
|
||||||
0x82,
|
// 0x82,
|
||||||
// 3 bmPINBlockString BYTE
|
// // 3 bmPINBlockString BYTE
|
||||||
// bits 7-4 bit size of PIN length in APDU
|
// // bits 7-4 bit size of PIN length in APDU
|
||||||
// bits 3-0 PIN block size in bytes after justification and formatting
|
// // bits 3-0 PIN block size in bytes after justification and formatting
|
||||||
fixedlen,
|
// fixedlen,
|
||||||
// 4 bmPINLengthFormat BYTE
|
// // 4 bmPINLengthFormat BYTE
|
||||||
// bits 7-5 RFU, bit 4 set if system units are bytes clear if
|
// // bits 7-5 RFU, bit 4 set if system units are bytes clear if
|
||||||
// system units are bits,
|
// // system units are bits,
|
||||||
// bits 3-0 PIN length position in system units
|
// // bits 3-0 PIN length position in system units
|
||||||
0x00,
|
// 0x00,
|
||||||
// 5 bInsertionOffsetOld BYTE Insertion position offset in bytes for
|
// // 5 bInsertionOffsetOld BYTE Insertion position offset in bytes for
|
||||||
// the current PIN
|
// // the current PIN
|
||||||
0x00,
|
// 0x00,
|
||||||
// 6 bInsertionOffsetNew BYTE Insertion position offset in bytes for
|
// // 6 bInsertionOffsetNew BYTE Insertion position offset in bytes for
|
||||||
// the new PIN
|
// // the new PIN
|
||||||
fixedlen,
|
// fixedlen,
|
||||||
// 7 wPINMaxExtraDigit USHORT XXYY, where XX is minimum PIN size
|
// // 7 wPINMaxExtraDigit USHORT XXYY, where XX is minimum PIN size
|
||||||
// in digits, YY is maximum
|
// // in digits, YY is maximum
|
||||||
pin_max_size,
|
// pin_max_size,
|
||||||
pin_min_size,
|
// pin_min_size,
|
||||||
// 9 bConfirmPIN
|
// // 9 bConfirmPIN
|
||||||
0x03, // TODO check?
|
// 0x03, // TODO check?
|
||||||
// 10 bEntryValidationCondition BYTE Conditions under which PIN
|
// // 10 bEntryValidationCondition BYTE Conditions under which PIN
|
||||||
// entry should be considered complete.
|
// // entry should be considered complete.
|
||||||
//
|
// //
|
||||||
// table for bEntryValidationCondition:
|
// // table for bEntryValidationCondition:
|
||||||
// 0x01: Max size reached
|
// // 0x01: Max size reached
|
||||||
// 0x02: Validation key pressed
|
// // 0x02: Validation key pressed
|
||||||
// 0x04: Timeout occurred
|
// // 0x04: Timeout occurred
|
||||||
0x07,
|
// 0x07,
|
||||||
// 11 bNumberMessage BYTE Number of messages to display for PIN
|
// // 11 bNumberMessage BYTE Number of messages to display for PIN
|
||||||
// verification
|
// // verification
|
||||||
0x03, // TODO check? (match with bConfirmPIN?)
|
// 0x03, // TODO check? (match with bConfirmPIN?)
|
||||||
// 12 wLangId USHORT Language for messages
|
// // 12 wLangId USHORT Language for messages
|
||||||
0x04,
|
// 0x04,
|
||||||
0x09, // US english
|
// 0x09, // US english
|
||||||
// 14 bMsgIndex1-3
|
// // 14 bMsgIndex1-3
|
||||||
0x00,
|
// 0x00,
|
||||||
0x01,
|
// 0x01,
|
||||||
0x02,
|
// 0x02,
|
||||||
// 17 bTeoPrologue BYTE[3] T=1 I-block prologue field to use (fill with 00)
|
// // 17 bTeoPrologue BYTE[3] T=1 I-block prologue field to use (fill with 00)
|
||||||
0x00,
|
// 0x00,
|
||||||
0x00,
|
// 0x00,
|
||||||
0x00,
|
// 0x00,
|
||||||
];
|
// ];
|
||||||
|
//
|
||||||
// 15 ulDataLength ULONG length of Data to be sent to the ICC
|
// // 15 ulDataLength ULONG length of Data to be sent to the ICC
|
||||||
send.extend(&(ab_data.len() as u32).to_le_bytes());
|
// send.extend(&(ab_data.len() as u32).to_le_bytes());
|
||||||
|
//
|
||||||
// 19 abData BYTE[] Data to send to the ICC
|
// // 19 abData BYTE[] Data to send to the ICC
|
||||||
send.extend(ab_data);
|
// send.extend(ab_data);
|
||||||
|
//
|
||||||
log::debug!("pcsc pinpad_modify send: {:x?}", send);
|
// log::debug!("pcsc pinpad_modify send: {:x?}", send);
|
||||||
|
//
|
||||||
let mut recv = vec![0xAA; 256];
|
// let mut recv = vec![0xAA; 256];
|
||||||
|
//
|
||||||
let modify_ioctl: [u8; 4] = self
|
// let modify_ioctl: [u8; 4] = self
|
||||||
.reader_caps
|
// .reader_caps
|
||||||
.get(&FEATURE_MODIFY_PIN_DIRECT)
|
// .get(&FEATURE_MODIFY_PIN_DIRECT)
|
||||||
.ok_or_else(|| anyhow!("no reader_capability"))?
|
// .ok_or_else(|| anyhow!("no reader_capability"))?
|
||||||
.value()
|
// .value()
|
||||||
.try_into()?;
|
// .try_into()?;
|
||||||
|
//
|
||||||
let res = self.card.control(
|
// let res = self.card.control(
|
||||||
u32::from_be_bytes(modify_ioctl).into(),
|
// u32::from_be_bytes(modify_ioctl).into(),
|
||||||
&send,
|
// &send,
|
||||||
&mut recv,
|
// &mut recv,
|
||||||
)?;
|
// )?;
|
||||||
|
//
|
||||||
log::debug!(" <- pcsc pinpad_modify result: {:x?}", res);
|
// log::debug!(" <- pcsc pinpad_modify result: {:x?}", res);
|
||||||
|
//
|
||||||
Ok(res.to_vec())
|
// Ok(res.to_vec())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
Loading…
Reference in a new issue