Browse Source

Add better FCP reading, hopeful osx support and stop scanning default af by default.

tags/v0.2
Thomas Kerber 3 years ago
parent
commit
864907ecef
5 changed files with 57 additions and 47 deletions
  1. 2
    1
      README.md
  2. 3
    19
      src/fs/mod.rs
  3. 5
    3
      src/fs/path.rs
  4. 41
    23
      src/pcsc.rs
  5. 6
    1
      src/scan.rs

+ 2
- 1
README.md View File

@@ -21,7 +21,8 @@ a while. For a list of options, run `troll help scan`. In particular, the
`--pin` option for logging in (this is more important during the extraction
phase however), and `--af` for supplying the AF names on the card. Troll can
also attempt to extract available AFs from EF.DIR, however many proprietary
cards do not supply this.
cards do not supply this. If not `--af` flag is supplied, troll will scan the
default af only.

It may happen that troll encounters some recursive directory structures. Use
the `--filter` flag to apply basic filtering rules to attempt to catch these.

+ 3
- 19
src/fs/mod.rs View File

@@ -414,20 +414,11 @@ impl Capabilities {
if test_result(&try!(handle.send_apdu(cla, 0xb2, 0x01, 0x14, &[], 0x00))[..]) {
ret.add(Capability::ReadRecordShortEF);
}
if test_result(&try!(handle.send_apdu(cla, 0xca, 0x00, 0x00, &[], 0x00))[..]) {
let res = try!(handle.send_apdu(cla, 0xca, 0x00, 0x00, &[], 0x00));
if &res[..] == &[0x6a, 0x86] || test_result(&res[..]) {
ret.add(Capability::ReadData);
}
// Filter out ReturnFCP and ReturnFMD that lie.
if ret.has(Capability::SelectMF) {
let res = try!(handle.send_apdu(cla, 0xa4, 0x00, 0x04, &[0x3f, 0x00], 0x00));
if res.len() != 2 || res[0] != 0x61 {
ret.rm(Capability::ReturnFCP);
}
let res = try!(handle.send_apdu(cla, 0xa4, 0x00, 0x08, &[0x3f, 0x00], 0x00));
if res.len() != 2 || res[0] != 0x61 {
ret.rm(Capability::ReturnFMD);
}
}
info!("Card capabilities: {:?}", ret.list());
Ok(ret)
}

@@ -436,13 +427,6 @@ impl Capabilities {
self
}

pub fn rm(&mut self, c: Capability) -> &mut Self {
if self.has(c) {
self.0 -= c.raw();
}
self
}

pub fn has(&self, c: Capability) -> bool {
(self.0 & c.raw()) != 0
}

+ 5
- 3
src/fs/path.rs View File

@@ -45,13 +45,15 @@ impl<'a, 'b: 'a> FileSystemHandle for PathHandle<'a, 'b> {
}
data[l-2] = i as u8;
data[l-1] = j as u8;
let res = try!(self.send_apdu(0xa4, 0x08, 0x04, &data[..], 0x00));
let res = try!(self.send_apdu(0xa4, 0x08, 0x04, &data[..], 0x100));
if &res[res.len()-2..] == &[0x6a, 0x82] {
continue;
}
try!(try_sw(&res[..]));
let df = if res[res.len()-2] != 0x61 {
warn!("Error termining if {} is DF: {}",
let df = if res[res.len()-2] == 0x90 {
is_df_fcp(&res[..res.len()-2])
} else if res[res.len()-2] != 0x61 {
warn!("Error determining if {} is DF: {}",
data.to_hex(),
Error::unexpected_result("expected response FCP template", res));
true

+ 41
- 23
src/pcsc.rs View File

@@ -3,21 +3,37 @@ use std::ffi::CStr;
use std::ptr::{null, null_mut};
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display, Formatter};
use self::libc::{c_void, c_ulong, c_char, c_long};
use self::libc::{c_void, c_ulong, c_char, c_long, c_uchar};
use rustc_serialize::hex::{ToHex};

#[repr(C)]
struct SCardIORequest(c_ulong, c_ulong, c_long);
struct SCardIORequest(c_ulong, c_ulong);

#[cfg(target_os="macos")]
type CDWord = u32;
#[cfg(target_os="macos")]
type CByte = u8;
#[cfg(target_os="macos")]
type CLong = i32;
#[cfg(not(target_os="macos"))]
type CDWord = c_ulong;
#[cfg(not(target_os="macos"))]
type CByte = c_uchar;
#[cfg(not(target_os="macos"))]
type CLong = c_long;

type CContext = CLong;
type CHandle = CLong;

#[link(name="pcsclite")]
extern {
fn SCardEstablishContext(scope: c_ulong, res1: *mut c_void, res2: *mut c_void, context: *mut c_ulong) -> c_long;
fn SCardReleaseContext(context: c_ulong) -> c_long;
fn SCardListReaders(context: c_ulong, groups: *const u8, readers: *mut u8, readerslen: *mut c_ulong) -> c_long;
fn SCardConnect(context: c_ulong, reader: *const u8, share_mode: c_ulong, preferred_protocols: c_ulong, handle: *mut c_ulong, active_procotol: *mut c_ulong) -> c_long;
fn SCardDisconnect(handle: c_ulong, disposition: c_ulong) -> c_long;
fn SCardTransmit(handle: c_ulong, sendPci: *const SCardIORequest, sendBuffer: *const u8, sendLength: c_ulong, recvPci: *const SCardIORequest, recvBuffer: *mut u8, recvLength: *mut c_ulong) -> c_long;
fn pcsc_stringify_error(err: c_long) -> *const c_char;
fn SCardEstablishContext(scope: CDWord, res1: *mut c_void, res2: *mut c_void, context: *mut CContext) -> CLong;
fn SCardReleaseContext(context: CContext) -> CLong;
fn SCardListReaders(context: CContext, groups: *const c_char, readers: *mut c_char, readerslen: *mut CDWord) -> CLong;
fn SCardConnect(context: CContext, reader: *const c_char, share_mode: CDWord, preferred_protocols: CDWord, handle: *mut CHandle, active_procotol: *mut CDWord) -> CLong;
fn SCardDisconnect(handle: CHandle, disposition: CDWord) -> CLong;
fn SCardTransmit(handle: CHandle, sendPci: *const SCardIORequest, sendBuffer: *const CByte, sendLength: CDWord, recvPci: *const SCardIORequest, recvBuffer: *mut CByte, recvLength: *mut CDWord) -> CLong;
fn pcsc_stringify_error(err: CLong) -> *const c_char;
static g_rgSCardT0Pci: SCardIORequest;
static g_rgSCardT1Pci: SCardIORequest;
static g_rgSCardRawPci: SCardIORequest;
@@ -30,7 +46,7 @@ pub enum ShareMode {
}

impl ShareMode {
fn raw(&self) -> c_ulong {
fn raw(&self) -> CDWord {
match self {
&ShareMode::Exclusive => 1,
&ShareMode::Shared => 2,
@@ -48,7 +64,7 @@ pub enum Protocol {
}

impl Protocol {
fn raw(&self) -> c_ulong {
fn raw(&self) -> CDWord {
match self {
&Protocol::Undefined => 0,
&Protocol::T0 => 1,
@@ -57,7 +73,7 @@ impl Protocol {
}
}

fn from_raw(raw: c_ulong) -> Self {
fn from_raw(raw: CDWord) -> Self {
match raw {
1 => Protocol::T0,
2 => Protocol::T1,
@@ -84,7 +100,7 @@ pub enum Scope {
}

impl Scope {
fn raw(self) -> c_ulong {
fn raw(self) -> CDWord {
match self {
Scope::User => 0,
Scope::Terminal => 1,
@@ -94,7 +110,7 @@ impl Scope {
}
}

pub struct Error(c_long);
pub struct Error(CLong);

impl StdError for Error {
fn description(&self) -> &str {
@@ -117,11 +133,11 @@ impl Debug for Error {
}
}

pub struct Context(c_ulong);
pub struct Context(CContext);

impl Context {
pub fn new(scope: Scope) -> Result<Self, Error> {
let mut c: c_ulong = 0;
let mut c: CContext = 0;
let err = unsafe {
SCardEstablishContext(scope.raw(), null_mut(), null_mut(), &mut c)
};
@@ -142,26 +158,26 @@ impl Drop for Context {
}
}

pub struct Handle<'a>(c_ulong, &'a Context, Protocol);
pub struct Handle<'a>(CHandle, &'a Context, Protocol);

impl<'a> Handle<'a> {
pub fn default(context: &'a Context, share_mode: ShareMode, preferred_protocols: &[Protocol]) -> Result<Self, Error> {
let mut readers_size: c_ulong = 0;
let mut readers_size: CDWord = 0;
let err = unsafe {
SCardListReaders(context.0, null(), null_mut(), &mut readers_size)
};
if err != 0 {
return Err(Error(err))
}
let mut readers = vec![0u8; readers_size as usize];
let mut readers = vec![0i8; readers_size as usize];
let err = unsafe {
SCardListReaders(context.0, null(), readers.as_mut_ptr(), &mut readers_size)
};
if err != 0 {
return Err(Error(err))
}
let mut handle: c_ulong = 0;
let mut active_protocol: c_ulong = 0;
let mut handle: CHandle = 0;
let mut active_protocol: CDWord = 0;
let mut preferred_protocols_raw = 0;
for p in preferred_protocols {
preferred_protocols_raw |= p.raw();
@@ -178,7 +194,7 @@ impl<'a> Handle<'a> {

pub fn send_apdu(&mut self, cla: u8, ins: u8, p1: u8, p2: u8, data: &[u8], retlen: u16) -> Result<Vec<u8>, Error> {
let mut res = vec![0u8; retlen as usize + 2];
let mut reslen = retlen as c_ulong + 2;
let mut reslen = retlen as CDWord + 2;
let mut cmd = Vec::with_capacity(6 + data.len());
cmd.push(cla);
cmd.push(ins);
@@ -190,6 +206,8 @@ impl<'a> Handle<'a> {
cmd.extend(data);
if retlen != 0 && retlen < 0x100{
cmd.push(retlen as u8);
} else if retlen == 0x100 {
cmd.push(0x00);
} else if retlen != 0 {
cmd.push(0u8);
cmd.push((retlen >> 8) as u8);
@@ -197,7 +215,7 @@ impl<'a> Handle<'a> {
}
debug!("APDU SEND: {}", cmd.to_hex());
let err = unsafe {
SCardTransmit(self.0, self.2.io_request(), cmd.as_ptr(), cmd.len() as c_ulong, null(), res.as_mut_ptr(), &mut reslen)
SCardTransmit(self.0, self.2.io_request(), cmd.as_ptr(), cmd.len() as CDWord, null(), res.as_mut_ptr(), &mut reslen)
};
if err == 0 {
res.truncate(reslen as usize);

+ 6
- 1
src/scan.rs View File

@@ -115,7 +115,7 @@ pub fn main(args: Vec<String>) {
exit(2);
}
};
let mut afs = vec![Vec::new()];
let mut afs = Vec::new();
for af in matches.opt_strs("a").iter() {
afs.push(match af.from_hex() {
Ok(v) => v,
@@ -128,6 +128,11 @@ pub fn main(args: Vec<String>) {
if matches.opt_present("ef-dir") {
unimplemented!();
}
if afs.len() == 0 {
afs.push(Vec::new());
} else {
afs.sort();
}
let caps = match fs::Capabilities::test_for(&mut handle, cla, true) {
Ok(v) => v,
Err(e) => {

Loading…
Cancel
Save